模板重载会导致链接器错误/奇怪的行为
template overloading results in linker error / strange behaviour
使用以下最小示例,我在 Visual Studio 15.8.7 中的本地系统上收到链接器错误(具有标准设置的标准控制台应用程序(刚刚删除了预编译标头((:"错误LNK1179无效或损坏的文件:重复的 COMDAT '??$f@H@@YAXH@Z'">
#include <cstdio>
template<typename T> void f(T) { printf("1"); } //#1. T can be deduced
template<typename T> void f(int) { printf("2"); } // #2. T needs to be specified explicitly
int main()
{
f(8); // a) calls #1
f<int>(8); // b) calls #2
}
- 注释掉调用 a( 或调用 b( 将导致成功链接。独立调用 a( 调用模板定义 #1。第二个调用 b( 调用模板定义 #2。不出所料。
- 在发布模式下生成成功。输出为 11。因此,这两个调用都调用模板定义 #1。意外。ODR违规?
- 此外,我观察到以下奇怪的行为(在调试设置中(:
- 我注释掉模板定义 #2
- 我进行全面重建
- 我在模板定义 #2 中评论
- 我建造(不是重建,只是建造(
- 构建成功
- 输出为 11 而不是 12
增量链接做奇怪的事情?
在 wandbox、godbolt 和 coliru 上,我可以编译、链接和运行,并获得 gcc 和 clang 的预期行为。
项目符号 3 中描述的观察结果使我认为这与增量链接有关。但也许代码也没有很好地定义?在学习 https://en.cppreference.com/w/cpp/language/function_template 时,我遇到了以下情况:
函数上调用两个涉及模板参数的表达式 等效,如果它们不等价,但对于任何给定的集合 模板参数,两个表达式的求值结果为 相同的值。
和
如果程序包含函数模板的声明,这些函数模板是 功能等效但不等效,程序格式不正确; 无需诊断。
那么,上面的代码是不是格式不正确?我是否违反了 ODR?还是一切都很好,它只是一个链接器/编译器错误?
编辑:固定点 3. 我在定义 #2 或课程中发表评论。
更新:新的一天,我想问题解决了。今天我无法重现该问题。我没有更改系统上的任何内容。我刚刚启动,打开我的项目,它像预期的那样工作。不知道发生了什么。但与学习新的特殊神秘模板重载规则相比,这种方式更好:-P
程序很好。您有两个不同的函数正在被调用。这是一个编译器和/或链接器错误。
[temp.over.link] 引出:
可以重载函数模板,以便两个不同的函数模板专用化具有相同的类型。
[ 示例:
// translation unit 1: template<class T> void f(T*); void g(int* p) { f(p); // calls f<int>(int*) } // translation unit 2: template<class T> void f(T); void h(int* p) { f(p); // calls f<int*>(int*) }
— 结束示例 ]
这种专业化是不同的功能,不违反单一定义规则。
您有两个不同的函数模板,句号。关于等价的措辞与模板参数和依赖表达式有关 ([temp.over.link]/5(:
涉及模板参数的两个表达式被视为等效,如果 [...]
int
不涉及模板参数,因此绝不能将其视为等同于T
。
- 错误 没有与参数列表匹配的重载函数"getline"实例
- 在运算符重载定义中使用成员函数(const错误)
- 重载方法的方式会在使用临时调用时生成编译器错误
- 数组索引重载错误
- C++:需要帮助了解运算符重载错误
- 在类Bat代码中,这给了我错误:重载的"Bat()"的调用是不明确的Bat(;)
- 不明确的错误重载运算符<<QdataStream 子类和个人类
- 具有相同参数的不同模板模板参数的错误重载函数
- 编译错误:重载函数的多个实例与 arument 列表匹配
- clang-libc++错误:重载解析选择了隐式删除的复制赋值运算符
- 错误:重载的调用不明确
- C++ 编译器选择输出流运算符<<的错误重载
- 分段错误重载运算符<<
- 错误:重载函数的多个实例与参数列表匹配
- 错误:重载的“max(int, int)”的调用不明确
- C++编译器选择类成员函数的错误重载
- 编译错误:重载操作符()
- 错误:重载的“bind(int(Class::*)(int,int),Class*,int,int”的调用不明确
- 未解析的外部符号错误重载操作符+模板
- 错误重载在构建"OpenSubdiv"时具有类似的转换