使用g ++编译时静态函数的模板特化

时间:2012-10-12 13:30:38

标签: c++ templates template-specialization

为什么在编译时使用以下代码不起作用:

$ g++ temp_main.cpp temp_spec.cpp
/tmp/ccirjc3Y.o:temp_spec.cpp:(.text+0x100): multiple definition of `my::say()'
/tmp/ccSo7IVO.o:temp_main.cpp:(.text$_ZN2myILi0EE3sayEv[my::say()]+0x0):
first defined here collect2: ld returned 1 exit status

我正在尝试仅在使用时具有静态功能的专业化 参数0。

temp_gen.h:

#ifndef temp_gen_h
#define temp_gen_h

#include <iostream>

template<int N>
struct my
{
   static void say();
};

template<int N>
void my<N>::say()
{
   std::cout << "generic " << N << std::endl;
}

#endif

temp_spec.h:

#ifndef temp_spec_h
#define temp_spec_h

#include <iostream>

#include "temp_gen.h"

template<>
void my<0>::say()
{
   std::cout << "specialized " << 0 << std::endl;
}

#endif

temp_spec.cpp:

#include "temp_spec.h"

temp_main.cpp:

#include "temp_gen.h"

int main(int argc, char* argv[])
{
   my<0>::say();  //should say "specialized 0"
   my<1>::say();  //should say "generic 0"
}

3 个答案:

答案 0 :(得分:2)

我相信,由于您的模板特化的实现位于标题中,因此您需要将其标记为inline,以便编译器/链接器知道您可以违反一个定义规则。

答案 1 :(得分:2)

main.cpp内,您没有专门化模板类,这是因为您没有包含temp_spec.h

正如Vaughn Cato指出的那样(参见评论),你应该将专门方法的定义(不再是模板方法)移到temp_spec.cpp

我认为(但我不是这方面的专家)你应该总是将专业化直接放在通用模板下面(在同一个头文件中),因为每当你包含它时,你也需要要定义的专门的,否则你会在发生这种错误时感到困惑。但是,您可以在temp_spec.h的底部添加temp_gen.h

此外,您不需要.cpp文件用于模板标头,因为永远不会有任何代码需要单独编译(模板类总是在使用它的另一个.cpp文件中编译,并且我认为在链接时会删除重复项,在链接时会导致麻烦再次出现没有专门化它,有一次 [本段仅适用于通用模板类,而不适用于(完全)专用类,因为它们需要在自己的编译单元中的某些代码,请参阅注释和上面的编辑。

答案 2 :(得分:1)

使用标准的n3337版本(强调我的):

  

14.7.3明确的专业化[temp.expl.spec]

     

6 / 如果模板,成员模板或类模板的成员是显式专用的,则应在首次使用该特化之前声明该特化,这将导致隐式实例化地方,在每个翻译单元中发生此类用途;无需诊断。

因为在mainmy<0>::say的特化不可见,所以会发生隐式实例化,最终会出现上述情况:无需诊断(来自编译器)。

请注意,专业化只能在声明其通用副本后声明。