类模板成员的特化

时间:2014-09-10 06:31:59

标签: c++ templates template-specialization

我有一个标题,其中包含一个带有模板成员的类以及该成员的一些特化:

#include <iostream>
class Foo {
public:
    template<typename T>
    void print(const T& t) {
        std::cout << t << std::endl;
    }
};

template<>
void Foo::print<int>(const int& t) {
    std::cout << t << std::endl;
}

此标头包含在多个源文件中。

如果我将专门化放在类定义中,那么GCC会抱怨:

error: explicit specialization in non-namespace scope ‘class Foo’

但是如果我在类定义之外移动专门化,那么VC ++会抱怨多重定义的符号。

这样做的正确方法是两个编译器都满意吗?

2 个答案:

答案 0 :(得分:6)

明确专门的模板函数不再是模板(它不再依赖于任何模板参数)。因此,它遵循一元定义规则作为普通函数。这意味着显式专用函数的定义应该在整个程序中只进行一次。即您必须将定义放入实现文件(.cpp文件)。

但是,您仍然必须在头文件中声明此特化(告诉编译器它实际存在)。即在头文件中你必须做

template<> 
void Foo::print<int>(const int& t);

(注意,根据标准要求,它应该在命名空间范围内完成,即在类定义之外。)

然后在一个实现文件中

template<>
void Foo::print<int>(const int& t) {
    std::cout << t << std::endl;
}

P.S。当然,就像任何其他函数一样,您可以声明它inline并将定义保留在头文件中。

答案 1 :(得分:0)

标准说(§14.7.3/ 12):

  

函数模板的显式特化仅在内联时才是内联的   使用内联说明符声明或定义为已删除,和   与其功能模板是否内联无关。

ODR将函数模板的特化化视为普通函数(无需专门化)。 如果在标题内定义特化,则必须使用inline说明符声明它,因此可以包含多个翻译单元。

如果要在源文件中定义它,则必须在标头内声明特殊化(在命名空间范围内):

template<>
void Foo::print<int>(const int&);

并将定义放在源文件

template<>
void Foo::print<int>(const int& t)
{
    std::cout << t << std::endl;
}

,就像你习惯了正常的功能一样。