foo.h中:
template<typename T> class Foo { public: static int bar(); };
foo.cc:
#include "foo.h" template<> int Foo<int>::bar() { return 1; } template<> int Foo<double>::bar() { return 2; }
main.cc:
#include <iostream> #include "foo.h" int main(int argc,char **argv) { std::cout << Foo<int>::bar() << std::endl; std::cout << Foo<double>::bar() << std::endl; return 0; }
该程序针对所有C标准(c 98,gnu 98,c 11和gnu 11)编译并链接到gcc 4.7.2.输出为:
1 2
这对我来说是有道理的.因为main.cc翻译单元没有看到bar()或它的任何特殊化的定义,所以它期望在某些其他翻译单元中对bar()的调用使用非特异性定义bar()的显式实例化.但是,由于名称变化是可预测的,因此foo.cc中的专业化具有与非特定定义的显式实例化相同的符号名称,因此main.cc能够使用这些专业化,而不会在该翻译单元中声明该特征.
我的问题是这是一个意外,还是C标准规定的这种行为?换句话说,这个代码是否可移植?
我可以找到的最相关的先前的问题是Declaration of template class member specialization,但不包括这种特殊情况.
(如果你想知道为什么这对我很重要,那是因为我使用这样的代码作为一种编译时查找表,如果我不声明专长,则会缩短.)
解决方法
(14.7.3/6) If a template,a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place,in every translation unit in which such a use occurs; no diagnostic is required. If the program does not provide a definition for an explicit specialization and either the specialization is used in a way that would cause an implicit instantiation to take place or the member is a virtual member function,the
program is ill-formed,no diagnostic required. An implicit instantiation is never generated for an explicit specialization that is declared but not defined. […]
我相信,这实际上只会在您的主要模板定义包含其中一个成员函数的非专门版本的定义时产生影响.因为在这种情况下,当没有声明明确的专业化时,现有的主要定义可能被用来内联编译代码,专业化最终不会被链接使用.
换句话说,如果主模板定义中没有包含成员函数的定义,那么您的链接器技巧可能会被期望在实践中运行,但它不符合标准说明的内容,并且可以让您一旦在主模板中添加内联函数定义,就会发生真正的麻烦.