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

Template specialization for static function when compiling with g++

本文关键字:专用 静态函数 g++ 编译 使用      更新时间:2023-10-16

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

$g++temp_main.cpp temp_spec.cpp/tmp/ccirjc3Y.o:temp_spec.cpp:(.text+0x100):"my::say()"的多重定义/tmp/ccSo7IVO.o:temp_main.cpp:(.text$_ZN2myLi0EE3sayEv[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"
}

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

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

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

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

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

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

14.7.3显式专业化[temp.exp.spec]

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

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

请注意,只有在声明了泛型对应项之后,才能声明专门化。