为什么在编译时使用以下代码不起作用:
$ 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"
}
答案 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 / 如果模板,成员模板或类模板的成员是显式专用的,则应在首次使用该特化之前声明该特化,这将导致隐式实例化地方,在每个翻译单元中发生此类用途;无需诊断。
因为在main
中my<0>::say
的特化不可见,所以会发生隐式实例化,最终会出现上述情况:无需诊断(来自编译器)。
请注意,专业化只能在声明其通用副本后声明。