我有一个标题,其中包含一个带有模板成员的类以及该成员的一些特化:
#include <iostream>
class Foo {
public:
template<typename T>
void print(const T& t) {
std::cout << t << std::endl;
}
};
template<>
void Foo::print<int>(const int& t) {
std::cout << t << std::endl;
}
此标头包含在多个源文件中。
如果我将专门化放在类定义中,那么GCC会抱怨:
error: explicit specialization in non-namespace scope ‘class Foo’
但是如果我在类定义之外移动专门化,那么VC ++会抱怨多重定义的符号。
这样做的正确方法是两个编译器都满意吗?
答案 0 :(得分:6)
明确专门的模板函数不再是模板(它不再依赖于任何模板参数)。因此,它遵循一元定义规则作为普通函数。这意味着显式专用函数的定义应该在整个程序中只进行一次。即您必须将定义放入实现文件(.cpp
文件)。
但是,您仍然必须在头文件中声明此特化(告诉编译器它实际存在)。即在头文件中你必须做
template<>
void Foo::print<int>(const int& t);
(注意,根据标准要求,它应该在命名空间范围内完成,即在类定义之外。)
然后在一个实现文件中
template<>
void Foo::print<int>(const int& t) {
std::cout << t << std::endl;
}
P.S。当然,就像任何其他函数一样,您可以声明它inline
并将定义保留在头文件中。
答案 1 :(得分:0)
标准说(§14.7.3/ 12):
函数模板的显式特化仅在内联时才是内联的 使用内联说明符声明或定义为已删除,和 与其功能模板是否内联无关。
ODR将函数模板的特化化视为普通函数(无需专门化)。
如果在标题内定义特化,则必须使用inline
说明符声明它,因此可以包含多个翻译单元。
如果要在源文件中定义它,则必须在标头内声明特殊化(在命名空间范围内):
template<>
void Foo::print<int>(const int&);
并将定义放在源文件
中template<>
void Foo::print<int>(const int& t)
{
std::cout << t << std::endl;
}
,就像你习惯了正常的功能一样。