Let's say I have this code
template<typename T2, typename T = int>
struct X
{
static double f;
};
template<typename T>
double X<T>::f = 14.0;
If I try to compile clang give me the following error
nested name specifier 'X::' for declaration does not refer into a class, class template or class template partial specialization
and for GCC :
error: template definition of non-template 'double X::f'
The question is :
Why the compiler want us to specialize the struct X like that :
template<typename T2>
struct X<T2,int>
{
static double f;
};
The first declaration has int
as a default argument, why the compiler don't choose this declaration ?
I searched in the standard anchor [temp.spec] but it didn't help.
I ask this question after answered this one on SO.
Thanks for your help !
"Why the compiler want us to specialize the struct X like that" - that's not what the error messages are saying. You don't need to do this, and you really shouldn't do it unless what you want is a partial specialization and a static member defined only for that partial specialization.
The problem is that
template<typename T2, typename T = int> struct X
is a class template that has two template parameters. The fact that the second one has a default template argument doesn't change the fact that there are still two parameters.So, you need to define your class template member as belonging to a class template with two parameters, like this:
The relevant paragraphs in the standard (N4527, the current draft):
[14.5.1p3]
[14.1p9]
As specified in the quote above, the actual names of the template parameters (
T2
andT
) don't matter, they can be different from the ones in the class template definition, but they need to be consistent within the definition of the member. That is, you can do thisand it will still define the member of the correct
X
class template. However, using the same names can make things easier to understand when reading the code.By defining the partial specialization before the definition of
f
in your original example,template<typename T> double X<T>::f = 14.0;
becomes a valid definition of the memberf
of the partial specializationtemplate<typename T2> struct X<T2,int>
, and only of that template (partial specializations are templates themselves). The memberf
of the primary templatetemplate<typename, typename> struct X
remains undefined.The relevant wording is in [14.5.5.3p1]: