【问题标题】:Optimization level affecting template overload resolution影响模板重载分辨率的优化级别
【发布时间】:2021-03-23 11:35:55
【问题描述】:

我遇到了关于模板重载解析的有趣行为,它在发布和调试构建之间有所不同。我希望能够理解编译器/链接器使用的规则,使其以这种方式运行。
我试着挖掘了一下,这就是我想出的:

S.h

#pragma once

#include <cstdint>
#include <iostream>
enum class Enumeration : uint32_t {
    A = 0,
    B
};
struct S {
    template<typename T>
    bool func(Enumeration en) {
        std::cout << "enum nonspec\n";
        return func<T>(static_cast<uint32_t>(en));
    }

    template<typename T>
    bool func(uint32_t en) {
        std::cout << "uint32_t nonspec\n";
        return func<T>(en);
    }
};

S.cpp

#include "S.h"
template<>
bool S::func<float>(uint32_t en) {
    std::cout << "float specialization\n";
    return en;
}

template<>
bool S::func<uint32_t>(uint32_t en) {
    std::cout << "uint32_t specialization\n";
    return en - 1;
}

ma​​in.cpp

#include "S.h"

int main() {
    S s;
    Enumeration a = Enumeration::B;
    s.func<float>(a);
    return 0;
}

我已经尝试编译各个编译单元(S.cpp.o、main.cpp.o 和生成的二进制文件)。 我发现结果完全取决于 main.cpp.o 编译的优化级别。

-O0 的输出是
enum nonspec
float specialization

-O1 的输出是
enum nonspec
uint32_t nonspec
uint32_t nonspec
float specialization

使用-O2-O3,输出为
enum nonspec
然后无限递归uint32_t nonspec

我检查了目标文件,-O0
0000000000000000 W bool S::func&lt;float&gt;(Enumeration)
0000000000000000 W bool S::func&lt;float&gt;(unsigned int),
-O1 只有
0000000000000000 W bool S::func&lt;float&gt;(unsigned int),
-O3 没有任何符号。

使用的编译器:gcc 版本 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)
使用的链接器:ldd (Ubuntu GLIBC 2.27-3ubuntu1.3) 2.27

我想我明白会发生什么,但我想知道这种行为是否基于任何规则。

【问题讨论】:

  • 您的专业化(声明)在其用法中不可见 -> 格式错误的 NDR。
  • 然后推理UB,格式错误的程序是没有意义的。
  • 是的,似乎可行的是 UB、IFNDR 的可能输出。

标签: c++ templates linker compiler-optimization


【解决方案1】:

C++ 标准要求所有模板特化在使用之前声明

[temp.expl.spec]/6:

如果模板、成员模板或类模板的成员是显式特化的,则该特化应在第一次使用会导致隐式实例化的特化之前声明, 在每个翻译单元中出现这种使用;不需要诊断。

如果程序没有为显式特化提供定义,并且特化的使用方式会导致隐式实例化,或者成员是虚拟成员函数,则程序是非良构的,不需要诊断。

所以程序格式不正确,NDR。编译器不需要发出错误或警告,并且在这种情况下发生的事情没有任何限制,因为它永远不会发生。所以无论是“有效”、“似乎有效”还是“无效”都是纯属意外。

可能发生的情况是,编译器的优化会内联调用,否则不会,这使得链接器仍然可以在链接时找到特化。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-24
    • 2015-10-22
    • 2015-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-16
    • 1970-01-01
    相关资源
    最近更新 更多