Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does a template specialization extend or override the generic template?

Tags:

c++

templates

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

template<>
struct A<int>{
    void method2(){}
 };

Will A<int> have both method1 and method2? And A<float> will only have method1 ?

like image 344
johnbakers Avatar asked May 27 '13 01:05

johnbakers


People also ask

What is the difference between partial specialization and template specialization?

Templates can have more than one parameter type. Some older compilers allow one only to specialize either all or none of the template's parameters. Compilers that support partial specialization allow the programmer to specialize some parameters while leaving the others generic.

What is the use of template specialization?

This is called template specialization. Template allows us to define generic classes and generic functions and thus provide support for generic programming. Generic programming is an approach where generic data types are used as parameters in algorithms so that they work for variety of suitable data types.

Can you have templates with two or more generic arguments?

CLASS TEMPLATE WITH MULTIPLE PARAMETERSWe can use more than one generic data type in a class template, and each generic data type is separated by the comma.

What does generic template mean?

The generic template is a simple structured message that includes a title, subtitle, image, and up to three buttons. You may also specify a default_action object that sets a URL that will be opened in the Messenger webview when the template is tapped.


2 Answers

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.

like image 167
jogojapan Avatar answered Sep 18 '22 14:09

jogojapan


@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> {}
};
like image 22
aschepler Avatar answered Sep 19 '22 14:09

aschepler