On this site there is the following paragraph:
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< parameters > required by the nested template.
I do not know what the highlighted section means. Does "otherwise" refer to the general case (in which template<> is not used) or to the exception case (in which template<> must be used)?
I would appreciate an explanation of that section.
This will be our template:
template< typename T>
struct A {
struct B {}; // member class
template<class U> struct C { }; // member class template
};
See the following code:
template<> // specialization
struct A<int> {
void f(int); // member function of a specialization
};
// template<> not used for a member of a specialization
void A<int>::f(int) { /* ... */ }
We are not using template<> while defining the member of a specialization, as this is a normal member class.
But, now see the next code:
template<> // specialization of a member class template
template<class U> struct A<char>::C {
void f();
};
// template<> is used when defining a member of an explicitly
// specialized member class template specialized as a class template
template<>
template<class U> void A<char>::C<U>::f() { /* ... */ }
Here we are specializing a member template of the defined template. That is why we will need to use template<> to pass the parameters that this member template needs. In this case class U is needed for defining our member template, so for passing that we will need the keyword template<>.
Related
template<class T> struct A {
struct B { };
template<class U> struct C {
void show();
};
};
template<>
template<>
void A<int>::C<int>::show(){ //#1
}
int main(){
}
Consider the above code, At #1, it's an explicit specialization definition for member of member class template. Some rules will be applied to it as the following specified:
temp.expl.spec#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. Members of an explicitly specialized class template are defined in the same manner as members of normal classes, and not using the template<> syntax. The same is true when defining a member of an explicitly specialized member class. However, template<> is used in defining a member of an explicitly specialized member class template that is specialized as a class template.
Firstly, what's explicitly specialized class? Does it refer to the entity which has explicit specialization declaration? It seems to it doesn't mean it, please look at the example in Explicitly specialized class part
template<> template<> class A<int>::B<double>;
According to that example, A<int> within the explicit specialization for member can be called a explicitly specialized class. So, In my first example A<int> and C<int> are all explicitly specialized class? I'm not sure. I feel the phrase explicitly specialized class is not clear in this section.
Please note the emphasized part, it means the enclosing class template explicit specialization shall appear in the same scope as that of explicit specialization definition for its member. The member is defined in global scope but there's no any explicit specialization definition for A<int> or C<int> that appears in the global scope. How to interpret this?
By the way, as a opposite example:
template<class T> struct A {
struct B { };
template<class U> struct C {
void show();
};
};
template<>
template<typename U>
struct A<int>::C{ //#2
void show();
};
template<>
template<typename U>
void A<int>::C<U>::show(){ //#3
}
int main(){
}
why such code is required an explicit specialization for class template C before #3, what's the difference between such two examples?
Explicitly specialized class
The phrase "explicitly specialized class" is unclear in this section,
temp.expl.spec#15
A member or a member template may be nested within many enclosing class templates. In an explicit specialization for such a member, the member declaration shall be preceded by a template<> for each enclosing class template that is explicitly specialized.
[ Example:
template<class T1> class A {
template<class T2> class B {
void mf();
};
};
template<> template<> class A<int>::B<double>;
template<> template<> void A<char>::B<char>::mf();
— end example ]
what's the explicitly specialized class mean, Is it refer to an entity that have a explicit specialization declaration or something others? It seems to no explicit specialization for A<int> in the above example.
There is no confusion there, you have to parse those statements (C++ and English) according to their grammatical structure. Source code is description of program in language understandable for humans. Programming language is a tool of human cooperation.
CWG529 removed need to understand intuitively by changing wording to explain order and content of template-ids.
Here you declared template of class A with template parameter T, which contains class B and a nested declaration of template class C with template parameter U, which contains a method show():
template<class T> struct A {
struct B { };
template<class U> struct C {
void show();
};
};
Here you declared, that for explicitly specialized template class A (which required to have it declared first) with T = int that there is a template class C which contains method show()
template<>
template<typename U>
struct A<int>::C{ //#2
void show();
};
This declaration doesn't contradict previous one, but because it's a specialization of class A, it may expand it! You can do this:
template<>
template<typename U>
struct A<int>::C{ //#4
void hide();
};
Which means that for any A with T=int, there is a template class C that got member hide(). But other A's will have template class C with member show(). What previous statement did that it removed any doubts about content of C for this A's specialization.
Now this only defines member function show() for all C's contained in A<int>:
template<>
template<typename U>
void A<int>::C<U>::show(){ //#3
}
You don't have an explicit specialization of C here, which is an enclosing class for show(). the memeber id show() is preceded by an unspecialized template-id template<typename U> ... C<U>. There is only a definition of member function but it requires a visible declaration of that template C - the #2 part. The visibility may be attained by various means and "the scope" mentioned is generalized description of it.
Omitting part #2 would be a semantic equivalent of writing:
class C;
void C::show() { // ill-formed - C is an incomplete type.
}
We would know that all of A's contain some class C, but we don't have a complete definition for that particular C in specialized A<int> (and it may be different).
This statement actually states that specialization C<int>nested in specialization A<int> contains show()
template<>
template<>
void A<int>::C<int>::show(){ //#1
}
Any possibility of contradiction, ambiguity or uncertainty (aside from undefined behavior) are leading to ill-formed code and rules are meant to form the framework of limitations against which the code should be checked. With absence of #2, the #3 at some point could be followed by #4, then the #3 statement would become illegal and thus it is deemed as such. #2 and #4 at same time would be two definitions of same thing which also leads either to ill-formed code if they are present in same unit, or they would lead to undefined behavior if they are present in separate units within program.
I must be missing something obvious here because this really came to me as a surprise.
The following code gives me the error: error: missing template arguments before ‘a’
template<int n=0>
class A {};
...
A a;
...
Is there a reason why a template with 1 parameter declared with a default value has to be instantiated specifying a value for it?
Can someone quote the standard?
A is still a template class. But you can omit the template parameter though:
template<int n=0>
class A {};
int main() {
A<> a;
// ^^
return 0;
}
See the live demo.
I think1 the relevant standard section is here
14.7 Template instantiation and specialization
...
3 An explicit specialization may be declared for a function template, a class template, a member of a class
template or a member template. An explicit specialization declaration is introduced by template<>. In
an explicit specialization declaration for a class template, a member of a class template or a class member
template, the name of the class that is explicitly specialized shall be a simple-template-id. In the explicit specialization declaration for a function template or a member function template, the name of the function
or member function explicitly specialized may be a template-id.
[Example:
template<class T = int> struct A {
static int x;
};
template<class U> void g(U) { }
template<> struct A<double> { }; // specialize for T == double
template<> struct A<> { }; // specialize for T == int
template<> void g(char) { } // specialize for U == char
// U is deduced from the parameter type
template<> void g<int>(int) { } // specialize for U == int
template<> int A<char>::x = 0; // specialize for T == char
template<class T = int> struct B {
static int x;
};
template<> int B<>::x = 1; // specialize for T == int
— end example ]
1)Sorry, I can't find a better standard cite / example. It doesn't cover exactly the OP's case, but demonstrates at least the same, that templates still need the <> angle brackets to be identified as templates (classes or functions).
possible workaround if it's important to disguise the nature of your object:
// the template class
template<int n=0>
class ReallyA {};
// an alias for the common case
using A = ReallyA<0>;
A a;
This is how the standard library defines std::string, for example.
using string = basic_string<char>;
According to 17.7.3 [temp.expl.spec] paragraph 5 (N4659),
... Members of an explicitly specialized class template are defined in the same manner as members of normal classes, and not using the template<> syntax. The same is true when defining a member of an explicitly specialized member class. However, template<> is used in defining a member of an explicitly specialized member class template that is specialized as a class template.
The explicit specialization of E definitely does not belong to the bold case, and it still needs template<>. Why is that?
template<class T> struct A {
enum E : T;
};
template<> enum A<int>::E : int { eint };
This paragraph is related to members of an explicitly specialized class template, but you have not explicitly specialized the class template. This is an example of the case it is talking about:
template<class T> struct A {
enum E : T;
};
template<> struct A<int> {
enum E : int;
};
enum A<int>::E : int { eint }; // no template<> here
In your example code, you have explicitly specialized a member of the primary template, which does require using template<>, as specified in the first paragraph.
1 An explicit specialization of any of the following:
...
(1.7) — member enumeration of a class template
...
can be declared by a declaration introduced by template<>; that is:
explicit-specialization:
template < > declaration
The underlying principle behind paragraph 5 is that once you've explicitly specialized a template, it is no longer a template, and you work with the specialization just like you would any other non-template entity.
While writing a small template metaprogramming library for personal use, I came across an interesting problem.
Since I was reusing a few partial specializations for some metafunctions, I decided I would put them under a common template class and use tags along with nested partial specialization to provide the differences in behaviour.
The problem is I am getting nonsensical (to me) results. Here is a minimal example that showcases what I am trying to do:
#include <iostream>
#include <cxxabi.h>
#include <typeinfo>
template <typename T>
const char * type_name()
{
return abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, nullptr);
}
template <typename... Args>
struct vargs {};
namespace details
{
template <typename K>
struct outer
{
template <typename Arg>
struct inner
{
using result = Arg;
};
};
}
struct tag {};
namespace details
{
template <>
template <typename Arg, typename... Args>
struct outer<tag>::inner<vargs<Arg, Args...>>
{
using result = typename outer<tag>::inner<Arg>::result;
};
}
template <typename T>
using test_t = typename details::outer<tag>::inner<T>::result;
int main()
{
using t = test_t<vargs<char, int>>;
std::cout << type_name<t>() << '\n';
return 0;
}
I am getting vargs<char, int> as output when using the 5.1.0 version of gcc and tag when using the 3.6.0 version of clang. My intention was for the above piece of code to print char so I am pretty baffled by these results.
Is the above piece of code legal or does it exhibit undefined behavior?
If it's legal what is the expected behavior according to the standard?
Your code is correct; out-of-class implicitly instantiated class template member class template partial specializations are intended to be allowed by the Standard, as long as they are defined early enough.
First, let's try for a minimal example - noting by the way that there's nothing here that requires C++11:
template<class T> struct A {
template<class T2> struct B { };
};
// implicitly instantiated class template member class template partial specialization
template<> template<class T2>
struct A<short>::B<T2*> { };
A<short>::B<int*> absip; // uses partial specialization?
As noted elsewhere MSVC and ICC use the partial specialization as expected; clang selects the partial specialization but messes up its type parameters, aliasing T2 to short instead of int; and gcc ignores the partial specialization entirely.
Why out-of-class implicitly instantiated class template member class template partial specialization is allowed
Put simply, none of the language that permits other forms of class template member class template definitions excludes out-of-class implicitly instantiated class template member class template partial specialization. In [temp.mem], we have:
1 - A template can be declared within a class or class template; such a template is called a member template. A
member template can be defined within or outside its class definition or class template definition. [...]
A class template partial specialization is a template declaration ([temp.class.spec]/1). In the same paragraph, there is an example of out-of-class nonspecialized class template member class template partial specialization ([temp.class.spec]/5):
template<class T> struct A {
struct C {
template<class T2> struct B { };
};
};
// partial specialization of A<T>::C::B<T2>
template<class T> template<class T2>
struct A<T>::C::B<T2*> { };
A<short>::C::B<int*> absip; // uses partial specialization
There is nothing here to indicate that the enclosing scope cannot be an implicit specialization of the enclosing class template.
Similarly, there are examples of in-class class template member class template partial specialization and out-of-class implicitly instantiated class template member class template full specialization ([temp.class.spec.mfunc]/2):
template<class T> struct A {
template<class T2> struct B {}; // #1
template<class T2> struct B<T2*> {}; // #2
};
template<> template<class T2> struct A<short>::B {}; // #3
A<char>::B<int*> abcip; // uses #2
A<short>::B<int*> absip; // uses #3
A<char>::B<int> abci; // uses #1
(clang (as of 3.7.0-svn235195) gets the second example wrong; it selects #2 instead of #3 for absip.)
While this does not explicitly mention out-of-class implicitly instantiated class template member class template partial specialization, it does not exclude it either; the reason it isn't here is that it's irrelevant for the particular point being made, which is about which primary template or partial template specializations are considered for a particular specialization.
Per [temp.class.spec]:
6 - [...] when the primary
template name is used, any previously-declared partial specializations of the primary template are also
considered.
In the above minimal example, A<short>::B<T2*> is a partial specialization of the primary template A<short>::B and so should be considered.
Why it might not be allowed
In other discussion we've seen mention that implicit instantiation (of the enclosing class template) could result in implicit instantiation of the definition of the primary template specialization to take place, resulting in an ill-formed program NDR i.e. UB; [templ.expl.spec]:
6 - If a template, a member template or a member of a class template is explicitly specialized then that specialization
shall be declared before the first use of that specialization that would cause an implicit instantiation
to take place, in every translation unit in which such a use occurs; no diagnostic is required. [...]
However, here the class template member class template is not used before it is instantiated.
What other people think
In DR1755 (active), the example given is:
template<typename A> struct X { template<typename B> struct Y; };
template struct X<int>;
template<typename A> template<typename B> struct X<A>::Y<B*> { int n; };
int k = X<int>::Y<int*>().n;
This is considered problematic only from the point of view of the existence of the second line instantiating the enclosing class. There was no suggestion from the submitter (Richard Smith) or from CWG that this might be invalid even in the absence of the second line.
In n4090, the example given is:
template<class T> struct A {
template<class U> struct B {int i; }; // #0
template<> struct B<float**> {int i2; }; // #1
// ...
};
// ...
template<> template<class U> // #6
struct A<char>::B<U*>{ int m; };
// ...
int a2 = A<char>::B<float**>{}.m; // Use #6 Not #1
Here the question raised is of precedence between an in-class class template member class template full specialization and an out-of-class class template instantiation member class template partial specialization; there is no suggestion that #6 would not be considered at all.
The C++ standard states:
A template defines a family of classes or functions.
template-declaration:
exportopt template < template-parameter-list > declaration
The declaration in a template-declaration shall
declare or define a function or a class, or
define a member function, a member class or a static data member of a class template or of a class nested within a class template, or
define a member template of a class or class template.
The third of these bullet points is what is confusing me. What is an example of "a member template of a class" in this context? A member function or nested class definition would be included in one of the first two categories. Surely there's no such thing as a templatised data member? Is this referring to typedefs?
A member template of a class is a member function that is itself a template, like these:
class test {
template <typename T> void foo(); // member template of class
};
template <typename T>
void test::foo<T>() {} // definition
template <typename T>
class test2 {
template <typename U> void foo(); // member template of class template
};
template <typename T>
template <typename U>
void test2<T>::foo<U>() {} // definition