鉴于:
template<class T>
struct test {
void foo(int b);
void testFunc( int a )
{
}
};
void test::foo(int b)
{
}
template<>
void test<float>::testFunc( int a )
{
}
void someFunction()
{
}
我们知道“test::foo
”在测试类中有一个声明,在类定义之外有一个定义。
我们也知道“someFunction
”有一个声明也是它的定义
以类似的方式“test::testFunc
”(非专业),有一个声明也是它的定义
专业化函数“test<float>::testFunc
”是否在类“test”中声明为“testFunc
”并单独定义,或者它的声明也是定义?
答案 0 :(得分:3)
示例中的显式特化是一个也是定义的声明。您也可以单独声明它:
template<>
void test<float>::testFunc( int a );
如果使用了该函数,链接器会期望它在某处定义。
类中的声明是成员函数模板的声明和定义。
BTW,foo应该这样定义:
template <class T>
void test<T>::foo(int b)
{
}
答案 1 :(得分:1)
我想补充@Vaughn提供的有用答案。
在test
的模板定义中,您有一个非定义的成员函数声明以及一个定义成员函数声明。但是,该函数定义和声明与周围的模板test<T>
相关联,而不是与最终将从中实例化的类test<float>
相关联!
如果从该模板隐式实例化test<float>
,例如在其上使用::
- 运算符(范围),或者通过创建具有该类型的变量定义等,那么声明但不一定 所有成员的定义也隐式实例化。所有这些都与test<float>
的成员有关。
因此,当您为test<float>::testFunc
编写明确的特化时,因为您使用::
来查看类test<float>
,所以该类被隐式实例化,并使用它的所有成员声明。
test<float>::testFunc
的定义仅在需要时实例化(例如,当您调用它时)。
您声明的显式特化然后重新声明以前隐式实例化的成员函数,并提供 与test<float>
相关联的定义。它是一个真正的函数,除非标记为inline
,否则无法在标题中安全地定义 - 否则当您将其标题包含多个标记时,您将面临“定义多次”错误的风险。
总结testFunc
存在哪些声明和定义及其来源:
通过模板定义:
test<T>::testFunc(int);
test<T>::testFunc(int) { }
编译器从test<T>::testFunc(int);
test<float>::testFunc(int);
您对test<T>::testFunc(int);
test<float>::testFunc(int);
test<float>::testFunc(int) { }
特别是,test<float>::testFunc
没有生成的定义。如果有,那么您的代码将是格式错误的,无需诊断,因为生成的定义会干扰您为同一函数提供定义的显式特化。但是这样的事情只有在你明确专门化之前导致它的实例化时才会发生。因此,如果将显式特化定义移动到.cpp
文件中(如果您不想将其设为inline
),请放置一个显式的专门化声明,就像@Vaughn演示一样进入标题。