模板专门化是否扩展或覆盖泛型模板

Does a template specialization extend or override the generic template?

本文关键字:覆盖 泛型 是否 专门化 扩展      更新时间:2023-10-16
template<typename T>
struct A{
    void method1(){}
 };
template<>
struct A<int>{
    void method2(){}
 };

A<int>是否同时具有method1和method2?而A<float>只有method1 ?

每个专门化都带来一个全新的数据类型(或者一个全新的模板,如果专门化只是部分的话)。来自标准(c++ 11):

(§14.5.5/2)每个类模板部分特化是一个不同的模板,应该为模板部分特化的成员提供定义(14.5.5.3)。

:

(§14.5.5.3/1)[…类模板部分特化的成员与主模板的成员无关。类模板部分特化成员的使用方式需要定义,必须定义;主模板成员的定义永远不能用作类模板部分专门化成员的定义。[…]

上述内容是在部分专门化的上下文中陈述的,但它也适用于显式专门化(就像您的情况一样),尽管标准对此没有明确说明。

还要注意,你不仅需要声明你想要在专门化中使用的所有成员函数,而且还需要定义它们(在这里,标准甚至对显式专门化也非常清楚):

(14.7.3/5)显式特化类的成员不是从类模板的成员声明中隐式实例化的;相反,如果需要的话,类模板专门化的成员本身应该被显式地定义。在这种情况下,类模板显式特化的定义应该在作用域中在定义成员的点。显式专门化类的定义与生成的专门化的定义无关。也就是说,它的成员不必具有与生成的专门化成员相同的名称、类型等。[…]

因此,确实,A<int>将只有method2(), A<float>将只有method1()作为成员。此外,如果您要在A<int>专门化中也引入method1(),则它不需要具有与A<float>::method1()相同的参数类型或返回类型。

请参阅@aschepler的答案,了解避免为int情况重写模板定义的可能方法。

@jogojapan的答案解释了这种语言的作用。如果您确实想为特定的专门化添加新成员,这里有一些变通方法:

template<typename T>
struct A_Base {
    void method1() {}
};
template<typename T>
struct A : public A_Base<T> {};
template<>
struct A<int>
  : public A_Base<int>
{
    void method2() {}
};

现在A<int>有成员method1method2,但是A<float>没有成员method2

OR(如果你可以修改主模板)…

#include <type_traits>
template<typename T>
struct A {
    void method1() {}
    template<int N=0>
    auto method2() ->
    typename std::enable_if<std::is_same<T, int>::value && N==N>::type
    {}
};

template<int N>N==N部分确保std::enable_if有一个依赖值,因此不会抱怨,直到有人实际上试图使用A<T>::method2和不正确的T参数。


由于这个问题和答案似乎仍然受到关注,因此在c++ 20中稍后的编辑中添加了它,您可以简单地这样做:

#include <type_traits>
template<typename T>
struct A {
    void method1() {}
    void method2() requires std::is_same_v<T, int> {}
};

专门化取代泛型模板。因此,A<int>将只有method2(),当然,A<double>将只有method1()