关于C++模板函数声明与定义的问题

关于C++模板函数声明与定义的问题



模板函数出现的问题

今天在写代码的时候,发现了一个关于模板函数的问题。如下所示,
demo.h代码

#ifndef DEMO_H
#define DEMO_H

class Demo {
public:
    Demo();
    virtual ~Demo();

    template <typename T>
    T add(T a, T b);
};

#endif  // DEMO_H

demo.cpp代码

#include "demo.h"

Demo::Demo() {
}

Demo::~Demo() {
}

template <typename T>
T Demo::add(T a, T b) {
    return a + b;
}

main.cpp代码

#include <iostream>
#include "demo.h"

int main(void) {
    Demo d;

    std::cout << d.add(1, 2) << std::endl;

    return 0;
}

本以为没有问题,然而在编译的时候却出现了报错。
函数模板编译出错

问题分析:我明明定义了成员函数的声明和实现,g++编译器却提示我编译找不到成员函数的定义。问题出现链接上!


模板函数问题解决

通常情况下,你会在.h文件中声明函数和类,而将它们的定义放置在一个单独的.cpp文件中。但是在使用模板时,这种习惯性做法将变得不再有用,因为当实例化一个模板时,编译器必须看到模板确切的定义,而不仅仅是它的声明。因此,最好的办法就是将模板的声明和定义都放置在同一个.h文件中。这就是为什么所有的STL头文件都包含模板定义的原因。 —— [ 任何时候都适用的20个C++技巧 ]


  • 标准要求编译器在实例化模板时必须在上下文中可以查看到其定义实体;而反过来,在看到实例化模板之前,编译器对模板的定义体是不处理的——原因很简单,编译器怎么会预先知道typename 实参是什么呢?因此模板的实例化与定义体必须放到同一翻译单元中。 —— [ 任何时候都适用的20个C++技巧 ]

  • 模板定义很特殊。由template<…> 处理的任何东西都意味着编译器在当时不为它分配存储空间,它一直处于等待状态直到被一个模板实例告知。在编译器和连接器的某一处,有一机制能去掉指定模板的多重定义。所以为了容易使用,几乎总是在头文件中放置全部的模板声明和定义。 —— [ 《C++编程思想》第15章(第300页)]

  • 对C++编译器而言,当调用函数的时候,编译器只需要看到函数的声明。当定义类类型的对象时,编译器只需要知道类的定义,而不需要知道类的实现代码。因此,因该将类的定义和函数声明放在头文件中,而普通函数和类成员函数的定义放在源文件中。

  • 但在处理模板函数和类模板时,问题发生了变化。要进行实例化模板函数和类模板,要求编译器在实例化模板时必须在上下文中可以查看到其定义实体;而反过来,在看到实例化模板之前,编译器对模板的定义体是不处理的——原因很简单,编译器怎么会预先知道 typename 实参是什么呢?因此模板的实例化与定义体必须放到同一翻译单元中。 —— [类模板和模板函数连接出错处理]

综上所述,只要将模板函数的声明和实现放在同一个文件中,一般是xxx.h文件中就可以正常编译!


参考博客:
https://blog.csdn.net/nyist327/article/details/38347049
https://blog.csdn.net/cllcsy/article/details/50485324


猜你喜欢

转载自blog.csdn.net/zhengqijun_/article/details/81159433