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

112 Views Asked by At

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.

3

There are 3 best solutions below

0
user12002570 On BEST ANSWER

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;
};
//this is an specialization and so we must use template<> prefix
template<> 
struct C<bool> {
    static int x;
};
//this is just ordinary out of class definition of data member `x`. That is, this is not a specialization and so we don't need the prefix template<>
int C<bool>::x = 0;

In the above example, first we have provided an explicit specialization for bool of the class template C itself which behaves like an ordinary class(in the sense that it is not a template declaration). The template<> prefix is needed here because we were providing a specialization. Next, we provide an ordinary out-of-class definition of the static data member x of the specialization that we provided. But here we don't need the template<> prefix because this is not a specialization. This is just an ordinary out-of-class definition of a static data member.

Example 2

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

template<>  // needed because this is not an ordinary out-of-class definition of data member x. Instead this is a specialization 
int C<bool>::x = 0;

In the above example, we have not provided any explicit specialization for class template C. Instead we are directly providing a specialization for the static data member x. This means that unlike example 1, here we are not providing an out-of-class definition of a static data member but instead we're providing a specialization. So in this case we need the template<> prefix.

TLDR

In example 1 int C<bool>::x = 0; is just an ordinary out-of-class definition of a static data member x and not a specialization, so we don't need the prefix template<> for this. Conversely, in example 2 template<> int C<bool>::x = 0; is a specialization of a static data member x and not an ordinary out-of-class definition. So in this case(example 2) the prefix template<> is needed.

6
273K On

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;
0
molbdnilo On

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.