C++ 模板必须在使用它们的同一翻译单元(.CPP 文件加上所有包含的头文件)中定义(给定完整的函数体)。在您的头文件中,您所做的一切都是声明(给定名称和签名)函数。结果是,当您包含 时base.h
,编译器看到的所有内容是:
class Base {
template <typename T> void test(T a);
}
这声明但不定义函数。要定义它,您必须包含一个函数体:
class Base {
template <typename T> void test(T a)
{
// do something cool with a here
}
}
之所以需要这样做,是因为 C++ 编译器“按需”为模板生成代码。例如,如果您调用:
Base obj;
obj.test< int >( 1 );
obj.test< char >( 'c' );
Base::test
编译器会根据模板生成两组机器码,一组用于 a int
,一组用于 a char
。这里的限制是Base::test
模板的定义必须在同一个翻译单元(.CPP 文件)中,否则编译器将不知道如何为每个版本的Base::test
函数构建机器代码。编译器一次只对一个翻译单元进行操作,因此它不知道您是否Base::test< T >
在其他一些 CPP 文件中进行了定义。它只能与手头的东西一起工作。
这与泛型在 C#、Java 和类似语言中的工作方式完全不同。就我个人而言,我喜欢将模板视为由编译器根据需要扩展的文本宏。这迫使我记住,模板函数的完整主体需要包含在使用它的任何 CPP 文件中。