Home > Mobile >  What is the need for having two different syntaxes for specializing data member of a class template
What is the need for having two different syntaxes for specializing data member of a class template

Time:05-11

I was writing an example involving specialization of class template where I noticed that the standard allows two different syntax for specialization of a data member as shown below:

template<typename T >
struct C {
    static int x;
};
template<> 
struct C<bool> {
    static int x;
};
//here we cannot write prefix template<> 
int C<bool>::x = 0;

As can be seen in the above example, we are not allowed to write the prefix template<> for defining the static data member x. And i understand this and have no problem with the above example. But when i modified the example to look like as shown below, i was surprised to see that we are allowed/required to write the prefix template for defining the static data member x:

template<typename T >
struct C {
    static int x;
};

template<>  //here why is the use of prefix template<> allowed/required? Why standard mandates that we cannot omit this prefix template<> here but in the previous example we can omit it
int C<bool>::x = 0;

As can be seen in the above modified example, we are required to use the prefix template<> for defining the same static data member x. My question is that why is there a difference in syntax for defining the same data member x in the above two examples. That is why the standard requires the use of prefix template<> in the second example. Why can't we omit that prefix in the second example just like first example. Does using the prefix template<> in the second example help solve some problem(like some ambiguity or something else).

PS: Note that my question is not about which statement from the standard allows this usage(since i already know using the below given quoted statement from cppreference) but about the rationale for allowing these two syntaxes(one that uses template<> and one that doesn't).


I also came across the following and the code example given in the mentioned link that explain how this is allowed:

When defining a member of an explicitly specialized class template outside the body of the class, the syntax template<> is not used, except if it's a member of an explicitly specialized member class template, which is specialized as a class template, because otherwise, the syntax would require such definition to begin with template required by the nested template .

The above quoted statement explains along with the example given there explains how the standard allows the above given examples in my question. But i am looking for a reason why is the prefix template<> mandated by the standard in the second example. Why standard doesn't allow the ommision of prefix template<> in the second example as in example 1.

CodePudding user response:

They aren't different syntaxes for the same thing, they are different syntaxes for different things.

The first specializes the entire struct, including all its members.
That is, the specialization C<bool>::x is already implied by the struct specialization, and you're not allowed to specialize twice.
int C<bool>::x = 0; is a regular definition of the static member in that specialization.

The second only specializes the member, not the struct, and defines it at the same time.

CodePudding user response:

The first

template<typename T >
struct C {
    static int x;
};

// This is the template specialisation for bool and all struct members
template<> 
struct C<bool> {
    static int x;
};

// This is the extraneous template specialisation for bool
// and the single struct member, already specialized above - error
// template<> 
// int C<bool>::x = 0;

The modified first example

template<typename T >
struct C {
    static int x;
};

// This is the template specialisation for bool and the single struct member
template<> 
int C<bool>::x = 0;

// This is the extraneous template specialisation for bool
// and all struct members, one of them is already specialized above - error
// template<> 
// struct C<bool> {
//    static int x;
// };

The second

template<typename T >
struct C {
    static int x;
};

// This is the unique template specialisation for bool - ok
template<>
int C<bool>::x = 0;

Another example

template<typename T >
struct C {
    static int x;
};

// This is the template specialisation for bool
template<> 
struct C<bool> {
    static int x;
};

// This is another template socialisation for int - ok
template<>
int C<int>::x = 0;

CodePudding user response:

Explicit specialization declaration of a class template is not a template declaration. [Source]. This means that when we provide an explicit specialization for a class template, it behaves like an ordinary class.

Now we can apply this to the examples given in question.

Example 1

template<typename T >
struct C {
    static int x;
};
template<> 
struct C<bool> {
    static int x;
};
//no need for template<> because the above provided epxlicit specialization declaration is not a template declaration
int C<bool>::x = 0;

In the above example, we have provided an explicit specialization for bool. This provided definition behaves like an ordinary(non template) class. Thus, there is no need to have a prefix template<> when defining the static data member x outside the class because the explicitly specialized class(which is an ordinary class) is used instead of the generic class template.

Example 2

template<typename T >
struct C {
    static int x;
};

template<>  // needed because we have not provided an explicit specialization so that the static data member that will be generated(from C<bool) using the generic class template 
int C<bool>::x = 0;

In the above example, we have not provided any explicit specialization for bool. So we need to write the prefix template<> because the generic class template will first be used to instantiate C<bool> along with the static data member x. So here the generic class template directly comes into play while instantiating the static data member while in example 1 the explicit specialization is used instead of the generic class template.

  • Related