模板重载会导致链接器错误/异常行为

时间:2018-10-16 14:44:38

标签: c++ linker language-lawyer overloading function-templates

在下面的最小示例中,我在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违规?
  • 此外,我在调试设置中观察到以下奇怪行为:
    1. 我注释掉了模板定义#2
    2. 我进行了全面重建
    3. 我在模板定义#2中发表评论
    4. 我构建(不重建,仅构建)
    5. 构建成功
    6. 输出是11而不是12

增量链接在做奇怪的事情?

在wandbox上,godbolt和coliru我可以编译,链接和运行,并获得gcc和clang的预期行为。

项目要点3中描述的观察结果使我认为它与增量链接有关。但是也许代码也没有很好地定义?在学习https://en.cppreference.com/w/cpp/language/function_template时,我遇到了以下问题:

  

在功能上调用了两个涉及模板参数的表达式   如果它们不等价,则等价,但对于任何给定的   模板参数,两个表达式的求和结果   相同的值。

  

如果程序包含以下功能模板的声明:   在功能上等效但不等效,程序格式错误;   无需诊断。

那么,以上代码是否构成错误?我是否违反ODR?还是一切都很好,它只是一个链接程序/编译器错误?

编辑:固定点3。我在定义#2或课程中进行评论。

更新:新的一天,我想问题解决了。今天,我无法重现问题。我没有更改系统上的任何内容。我刚启动,打开了我的项目,它按预期运行。不知道发生了什么事。但与学习新的特殊奥秘模板重载规则:-P

相比,这种方法更好

1 个答案:

答案 0 :(得分:2)

该程序很好。您有两个被调用的不同函数。这是编译器和/或链接器错误。

[temp.over.link]导致:

  

可以重载功能模板,以便两个不同的功能模板专长具有相同的类型。

     

[示例:

$Body = @"
    <html>
        <body style="font-family:calibri"> 
            <b>This is image 1</b>
            <img src='cid:TEST1.png'>
            <b>This is image 2</b>
            <img src='cid:Test2.png'>
        </body>
    </html>
"@

Send-MailMessage -To "Test@Test.com" `
    -from "Test2@Test.com" `
    -SmtpServer Test.smtp.com `
    -Subject "Hello" `
    -BodyAsHtml -body $body `
    -Attachments "C:\Test\TEST1.png", "C:\Test\TEST2.png"
     

-举个例子]

     

此类专业化是不同的功能,并且不违反一定义规则。

您有两个不同的功能模板,即句号。关于等价的措辞与模板参数和相关表达式([temp.over.link]/5)有关:

  

如果[...]

,则包含模板参数的两个表达式被认为是等效的。

// 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*) } 不包含模板参数,因此绝不等同于int