c++ - 为什么模板没有重新定义,为什么都写在头文件里了?

标签 c++ templates c++11 linker

如果我会这样写:

// 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;
}

我收到这样的链接器错误:

error LNK2005: "public: void __thiscall A::f(void)" (?f@A@@QAEXXZ) already defined in B.obj

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

最佳答案

这里有两个独立的效果:

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

    也就是把下面的代码放在一个header中,重复包含就可以了:

    struct Foo {
       void bar() {}   // "inline" implied
    };
    

    但如果定义不一致,它必须在单个翻译单元中。

  2. 函数模板可以重复定义,即使它们不是内联的。一般来说,模板机制已经需要处理模板的重复实例化,并在链接时处理重复数据删除。

    类模板的成员函数本身就是函数模板,因此是否将它们声明为内联并不重要。

关于c++ - 为什么模板没有重新定义,为什么都写在头文件里了?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36841401/

相关文章:

c++ - 将变量参数列表转发到模拟 std::thread

c++ - 如何从左到右计算一个字节中连续设置的位的数量,直到第一个 0?

c++ - 如何将 .cpp 源文件编译为 .dll?

c++ - 在以固定大小为模板的不同大小的缓冲区之间复制

c++ - 是否可以在编译 (g++) 之前使用实例化模板查看 C++ 代码?

c++ - g++ 和 clang++ 变量模板和 SFINAE 的不同行为

c++ - 重新分配智能指针

c++ - 逻辑错误、数组和类型定义

c++ - 为什么编译器不能决定在没有引用运算符的情况下调用哪个函数?

c++ - 使用模板打印一个类