Does a template specialization extend or override the generic template?

@jogojapan's answer explains what the language does. Here's a couple workarounds if you do want to add new members for a specific specialization:

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() {}
};

Now A<int> has members method1 and method2, but A<float> has no method2.

OR (if you can modify the primary template)...

#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
    {}
};

The template<int N> and N==N parts make sure std::enable_if has a dependent value and therefore doesn't complain until somebody actually tries to use A<T>::method2 with an incorrect T parameter.


And since this question and answer seem to still be getting attention, a much later edit to add that in C++20, you can simply do:

#include <type_traits>

template<typename T>
struct A {
    void method1() {}

    void method2() requires std::is_same_v<T, int> {}
};

Each specialization brings an entirely new data type into existence (or an entirely new template, if the specialization is only partial). From the Standard (C++11):

(§14.5.5/2) Each class template partial specialization is a distinct template and definitions shall be provided for the members of a template partial specialization (14.5.5.3).

And:

(§14.5.5.3/1) [...] The members of the class template partial specialization are unrelated to the members of the primary template. Class template partial specialization members that are used in a way that requires a definition shall be defined; the definitions of members of the primary template are never used as definitions for members of a class template partial specialization. [...]

The above is stated in the context of partial specializations, but it applies to explicit specializations (as in your case) as well, although the Standard does not say this very clearly.

Also note that you need not only declare all member functions that you want in a specialization, but you need to define them, too (here, the Standard is very clear even about explicit specializations):

(14.7.3/5) A member of an explicitly specialized class is not implicitly instantiated from the member declaration of the class template; instead, the member of the class template specialization shall itself be explicitly defined if its definition is required. In this case, the definition of the class template explicit specialization shall be in scope at the point at which the member is defined. The definition of an explicitly specialized class is unrelated to the definition of a generated specialization. That is, its members need not have the same names, types, etc. as the members of a generated specialization. [...]

So, indeed, A<int> will only have method2(), and A<float> will only have method1() as member. Furthermore, if you were to introduce method1() in the A<int> specialization as well, it needs not have the same argument types or return type as A<float>::method1().

See @aschepler's answer for possible ways to avoid having to rewrite the template definition for the int case.

Tags:

C++

Templates