为什么模板没有重新定义,为什么它都写在头文件中?

Nar*_*rek 2 c++ linker templates c++11

如果我会写这样的东西:

// A.h
#ifndef A_h
#define A_h
class A
{
public:
    void f();
};

void A::f()
{
}
#endif //A_h


// B.cpp
#include "A.h"

void foo()
{
    A a;
    a.f();
}


// C.cpp
#include "A.h"

void bar()
{
    A b;
    b.f();
}

// main.cpp
#include "B.cpp"
#include "C.cpp"
using namespace std;

int main()
{
    foo();
    bar();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我这样得到一个链接器错误:

错误LNK2005:已在B.obj中定义的"public:void __thiscall A :: f(void)"(?f @ A @@ QAEXXZ)

A类是类模板时,为什么不会发生同样的问题?最终它在编译期间变成了普通类(非模板类),对吧?出于这个原因,我期望与非模板类相同的行为,即链接器错误.

Ker*_* SB 5

这里有两个独立的效果:

  1. 脱节的成员函数定义是正常的函数定义,并且通过一个定义规则(ODR),它必须在链接中恰好出现一次.内联定义的成员函数是隐式的inline,ODR允许重复内联函数定义:

    也就是说,可以将以下代码放在标题中并重复包含它:

    struct Foo {
       void bar() {}   // "inline" implied
    };
    
    Run Code Online (Sandbox Code Playgroud)

    但如果您的定义不符合规定,则必须在单个翻译单元中.

  2. 功能模板可以重复定义,即使它们不是内联的.模板机制通常需要处理模板的重复实例化,以及链接时的重复数据删除.

    类模板的成员函数本身就是函数模板,因此无论是否声明它们都无关紧要inline.