3

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

$ g++ temp_main.cpp temp_spec.cpp
/tmp/ccirjc3Y.o:temp_spec.cpp:(.text+0x100): `my::say()' 的多重定义
/tmp/ccSo7IVO.o:temp_main.cpp:(.text$_ZN2myILi0EE3sayEv[my::say()]+0x0):
首先在这里定义 collect2: ld 返回 1 退出状态

我只在使用参数 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"
}
4

3 回答 3

2

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

于 2012-10-12T13:33:14.350 回答
2

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

正如 Vaughn Cato 指出的(见评论),您应该将专用方法(不再是模板方法)的定义temp_spec.cpp移动到.

我认为(但我不是这方面的专家)您应该始终将专业化直接放在通用模板下方(在同一个头文件中),因为每当您包含它时,您还希望定义专门化的模板,否则您将发生此类错误时会感到困惑。但是,您可以只temp_spec.htemp_gen.h.

此外,您不需要模板头文件的 .cpp 文件,因为永远不会有任何代码需要单独编译(模板类总是在使用它的另一个 .cpp 文件中编译,我认为重复的文件将被删除链接时,再次在链接时造成麻烦,在一种情况下你没有专门化它,一次你做了[本段仅适用于通用模板类,不适用于(完全)专用类,因为它们在自己的编译单元中需要一些代码,请参阅上面的注释和编辑。]

于 2012-10-12T13:39:40.313 回答
1

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

14.7.3 显式特化 [temp.expl.spec]

6/如果模板、成员模板或类模板的成员被显式特化,则该特化应在第一次使用该特化之前声明,这将导致发生隐式实例化,在每个翻译单元中使用发生;不需要诊断。

因为在不可见的mainmy<0>::say化中,会发生隐式实例化,并且您最终会遇到上述情况:不需要诊断(来自编译器)。

请注意,只能在声明其通用对应物之后才能声明特化。

于 2012-10-12T17:32:13.060 回答