Template struct with the default template argument is not instantiated - c++

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:
template<typename T2, typename T>
double X<T2, T>::f = 14.0;
The relevant paragraphs in the standard (N4527, the current draft):
[14.5.1p3]
When a member function, a member class, a member enumeration, a static
data member or a member template of a class template is defined
outside of the class template definition, the member definition is
defined as a template definition in which the template-parameters are
those of the class template. The names of the template parameters used
in the definition of the member may be different from the template
parameter names used in the class template definition. The template
argument list following the class template name in the member
definition shall name the parameters in the same order as the one used
in the template parameter list of the member. Each template parameter
pack shall be expanded with an ellipsis in the template argument list.
[14.1p9]
[...] A default template-argument shall not be specified in the
template-parameter-lists of the definition of a member of a class
template that appears outside of the member’s class. [...]
As specified in the quote above, the actual names of the template parameters (T2 and T) 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 this
template<typename T, typename U>
double X<T, U>::f = 14.0;
and 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 member f of the partial specialization template<typename T2> struct X<T2,int>, and only of that template (partial specializations are templates themselves). The member f of the primary template template<typename, typename> struct X remains undefined.
The relevant wording is in [14.5.5.3p1]:
The template parameter list of a member of a class template partial
specialization shall match the template parameter list of the class
template partial specialization. The template argument list of a
member of a class template partial specialization shall match the
template argument list of the class template partial specialization. A
class template specialization is a distinct template. The members of
the class template partial specialization are unrelated to the members
of the primary template. [...]

Related

C++ standard paragraph about member template specialization of unspecialized template

In the current draft of the C++ standard, the paragraph [temp.expl.spec]p.18 says:
A specialization of a member function template, member class template, or static data member template of a non-specialized class template is itself a template.
However, the above paragraph temp.expl.spec]p.17 states (my emphasis):
In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope, the member template and some of its enclosing class templates may remain unspecialized, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well. [...]
Therefore, it should be impossible to explicitly specialize a member template without specializing its enclosing class template, so [temp.expl.spec]p.18 is wrong. I highlighted the word explicitly because [temp.expl.spec]p.18 says "A specialization [...]". Specialization can have a lot of meanings, one of which could be explicit specialization.
I checked and [temp.expl.spec]p.18 appeared in the standard before [temp.expl.spec]p.17. For example, in the 1996 version of the standard [temp.expl.spec]p.18 is present while [temp.expl.spec]p.17 is not.
What is the original intended meaning of [temp.expl.spec]p.18?
Thank you.
There can be partial specialization of a member class template of a non-specialized class template.
Your point 17 prohibits full specialization of such a member; and point 18 clarifies that the partial specialization in this case is still a template.
The terminology "explicitly specialize" means fully specialize, and excludes partial specialization.
template<typename T>
struct A
{
template<typename U, typename V>
struct B
{
void f() {}
};
};
// OK: Partially specialize A<T>::B. This is a template
template<typename T>
template<typename U>
struct A<T>::B<U, int>
{
void g() {}
};

Defining a static data member of a templated class within a templated class

I have a class template inside of another class template. The inner class has a static data member. I am struggling to provide a definition for it. The below example works in clang 3.8 but not in gcc-7.1
template <typename T>
struct Out {
template <typename U>
struct In {
static int var;
};
};
template <typename T>
template <typename U>
int Out<T>::template In<U>::var;
gcc gives the error:
error: template definition of non-template ‘int Out<T>::In<U>::var’
int Out<T>::template In<U>::var;
^~~
What do I gotta do to make gcc happy?
Edit: turns out getting rid of template make this work:
template <typename T>
template <typename U>
int Out<T>::In<U>::var;
Which still leaves the question, is template allowed here?
This type of definition would more commonly be seen without the template before In. The template keyword is not needed here because Out<T>::In is a "member of the current specialization".
For the rule specifying when the template keyword is required before a member name, see [temp.names]/4. For the definition of the technical term "member of the current specialization", see [temp.dep.type]/4.
But the keyword is in fact allowed there, since the grammar permits it between any :: and name, and the semantics require only that the name that follows is either used with template arguments or names a class template ([temp.names]/5), and there are no other rules in the Standard to forbid it. And as a note in [temp.names]/5 explains:
[ Note: As is the case with the typename prefix, the template prefix is allowed in cases where it is not strictly necessary; i.e., when the nested-name-specifier or the expression on the left of the -> or . is not dependent on a template parameter, or the use does not appear in the scope of a template. - end note]

Why the common template method definition doesn't match the template class specialization?

I have the following code:
template <class T, class U = T>
class A {
public:
void f();
};
template <class T>
class A<T, T> {
public:
void f(); // Unaltered method.
// Some differences.
};
template <class T, class U>
void A<T, U>::f() {}
int main() {
A<int> a;
a.f();
return 0;
}
The clang++ -std=c++11 test.cc gives me an error: undefined reference to 'A<int, int>::f()'
Why the provided definition of method f() doesn't apply to the class A<int, int>?
The primary class template template <class T, class U = T> class A and the partial specialization template <class T> class A<T, T> are two distinct template definitions. After they've been defined, whenever you refer to the class template name A, the primary template and all partial specializations will always be considered.
Whenever you instantiate A with either a single template argument, or two arguments of the same type, it'll form a better match for the specialization you've provided, and the primary template is not considered.
In your example, because of the partial specialization you've provided, there's no way to match the primary template, regardless of the default template argument, if you try to instantiate A with a single template argument, or two of the same type.
The solution, of course, is to provide the definition for A<T, T>::f()
template <class T>
void A<T, T>::f() {}
EDIT:In the presence of partial specializations, the rules for matching them are given by (from N3797) §14.5.5.1/1 [temp.class.spec.match]
When a class template is used in a context that requires an
instantiation of the class, it is necessary to determine whether the
instantiation is to be generated using the primary template or one of
the partial specializations. This is done by matching the template
arguments of the class template specialization with the template
argument lists of the partial specializations.
— If exactly one matching specialization is found, the instantiation is generated from that specialization.
— If more than one matching specialization is found, the partial order rules (14.5.5.2) are used to determine whether one of the
specializations is more specialized than the others. ...
— If no matches are found, the instantiation is generated from the primary template.
In your example the first rule applies, and the compiler doesn't even get to the 3rd rule.
When you define a member function of a class template outside the class, you are just defining the function for the corresponding function that was declared in the class template. You are not creating a new function template which might match other parameters. In your example:
template <class T, class U = T>
class A {
public:
void f(); // This is the declaration of A<T,U>::f()
};
template <class T>
class A<T, T> {
public:
void f(); // This is the declaration of A<T,T>::f()
};
template <class T, class U>
void A<T, U>::f() {} // This is the definition of A<T,U>::f()
// There is no definition of A<T,T>::f()
I believe what you are thinking is that the compiler will see that you are calling A<int,int>::f() and will look through the member function definitions and find one that matches, but this is not what happens. The compiler always looks through the class templates to find which function to call, and once it has found a match, it then looks for the corresponding definition. In your case, you are calling A<int,int>::f(), so it first looks for a class definition that matches A<int,int> and it finds your A<T,T> class template specialization. It sees that A<T,T> does indeed have a member function called f which matches your function call, which means A<T,T>::f() needs to be instantiated. To instantiate A<T,T>::f(), the compiler looks for the definition of A<T,T>::f(), however it doesn't find it. It only finds the definition of A<T,U>::f, which isn't a match. The template parameter matching that is used to find a proper function declaration doesn't apply.

What is this template construct?

This is from the C++ Standard Library xutility header that ships with VS2012.
template<class _Elem1,
class _Elem2>
struct _Ptr_cat_helper
{ // determines pointer category, nonscalar by default
typedef _Nonscalar_ptr_iterator_tag type;
};
template<class _Elem>
struct _Ptr_cat_helper<_Elem, _Elem>
{ // determines pointer category, common type
typedef typename _If<is_scalar<_Elem>::value,
_Scalar_ptr_iterator_tag,
_Nonscalar_ptr_iterator_tag>::type type;
};
Specifically what is the nature of the second _Ptr_cat_helper declaration? The angle brackets after the declarator _Ptr_cat_helper make it look like a specialization. But instead of specifying full or partial types by which to specialize the template it instead just repeats the template argument multiple times.
I don't think I've seen that before. What is it?
UPDATE
We are all clear that the specialization applies to an instantiation of the template where both template arguments are of the same type, but I'm not clear on whether this constitutes a full or a partial specialization, or why.
I thought a specialization was a full specialization when all the template arguments are either explicitly supplied or are supplied by default arguments, and are used exactly as supplied to instantiate the template, and that conversely a specialization was partial either, if not all the template parameters were required due to the specialization supplying one or more (but not all) of them, and/or if the template arguments were used in a form that was modified by the specialization pattern. E.g.
A specialization that is partial because the specialization is supplying at least one, but not all, of the template arguments.
template<typename T, typename U>
class G { public: T Foo(T a, U b){ return a + b; }};
template<typename T>
class G<T, bool> { public: T Foo(T a, bool b){ return b ? ++a : a; }};
A specialization that is partial because the specialization is causing the supplied template argument to be used only partially.
template<typename T>
class F { public: T Foo(T a){ return ++a; }};
template<typename T>
class F<T*> { public: T Foo(T* a){ return ++*a; }};
In this second example if the template were instantiated using A<char*&GT; then T within the template would actually be of type char, i.e. the template argument as supplied is used only partially due to the application of the specialization pattern.
If that is correct then wouldn't that make the template in the original question a full specialization rather than a partial specialization, and if that is not so then where is my misunderstanding?
It is a partial class template specialization for the case when the same type is passed for both parameters.
Maybe this will be easier to read:
template<typename T, typename U>
struct is_same : std::false_type {};
template<typename T>
struct is_same<T,T> : std::true_type {};
EDIT:
When in doubt whether a specialization is an explicit (full) specialization or a partial specialization, you can refer to the standard which is pretty clear on this matter:
n3337, 14.7.3./1
An explicit specialization of any of the following:
[...]
can be declared by a declaration introduced by template<>; that is:
explicit-specialization:
template < > declaration
and n3337, 14.5.5/1
A primary class template declaration is one in which the class
template name is an identifier. A template declaration in which the
class template name is a simple-template-id is a partial
specialization of the class template named in the simple-template-id. [...]
Where simple-template-id is defined in the grammar like this:
simple-template-id:
template-name < template-argument-list opt >
template-name
identifier
So, wherever there's template<>, it's a full specialization, anything else is a partial specialization.
You can also think about it this way: Full template specialization specializes for exactly one possible instantiation of the primary template. Anything else is a partial specialization. Example in your question is a partial specialization because while it limits the arguments to be of the same type, it still allows for indifinitely many distinct arguments the template can be instantiated with.
A specialization like this, for example
template<>
vector<bool> { /* ... */ };
is a full specialization because it kicks in when the type is bool and only bool.
Hope that helps.
And just a note I feel it's worth mentioning. I guess you already know - function templates can't be partialy specialized. While this
template<typename T>
void foo(T);
template<typename T>
void foo(T*);
might looks like a partial specialization of foo for pointers on the first glance, it is not - it's an overload.
You mention specifying "full or partial types" when performing specialization of a template, which suggests that you are aware of such language feature as partial specialization of class templates.
Partial specialization has rather extensive functionality. It is not limited to simply specifying concrete arguments for some of the template parameters. It also allows defining a dedicated version of template for a certain groups of argument types, based on their cv-qualifications or levels of indirection, as in the following example
template <typename A, typename B> struct S {};
// Main template
template <typename A, typename B> struct S<A *, B *> {};
// Specialization for two pointer types
template <typename A, typename B> struct S<const A, volatile B> {};
// Specialization for const-qualified type `A` and volatile-qualified type `B`
And it also covers specializations based on whether some template arguments are identical or different
template <typename A> struct S<A, A> {};
// Specialization for two identical arguments
template <typename A> struct S<A, A *> {};
// Specialization for when the second type is a pointer to the first one
As another, rather curios example, partial specialization of a multi-argument template can be used to fully override the main template
template <typename A, typename B> struct S<B, A> {};
// Specialization for all arguments
Now, returning to your code sample, partial specialization for two identical arguments is exactly what is used in the code you posted.

what does template<> (without any class T in the <>) mean?

I'm reading some source code in stl_construct.h,
In most cases it has sth in the <>
and i see some lines with only "template<> ...".
what's this?
This would mean that what follows is a template specialization.
Guess, I completely misread the Q and answered something that was not being asked.
So here I answer the Q being asked:
It is an Explicit Specialization with an empty template argument list.
When you instantiate a template with a given set of template arguments the compiler generates a new definition based on those template arguments. But there is a facility to override this behavior of definition generation. Instead of compiler generating the definition We can specify the definition the compiler should use for a given set of template arguments. This is called explicit specialization.
The template<> prefix indicates that the following template declaration takes no template parameters.
Explicit specialization can be applied to:
Function or class template
Member function of a class template
Static data member of a class template
Member class of a class template
Member function template of a class template &
Member class template of a class template
It's a template specialization where all template parameters are fully specified, and there happens to be no parameters left in the <>.
For example:
template<class A, class B> // base template
struct Something
{
// do something here
};
template<class A> // specialize for B = int
struct Something<A, int>
{
// do something different here
};
template<> // specialize both parameters
struct Something<double, int>
{
// do something here too
};