template<typename T>
struct A{
void method1(){}
};
template<>
struct A<int>{
void method2(){}
};
Will A<int> have both method1 and method2? And A<float> will only have method1 ?
Each specialization brings an entirely new data type into existence (or an entirely new template, if the specialization is only partial). From the Standard (C++11):
(§14.5.5/2) Each class template partial specialization is a distinct template and definitions shall be provided for the members of a template partial specialization (14.5.5.3).
And:
(§14.5.5.3/1) [...] The members of the class template partial specialization are unrelated to the members of the primary template. Class template partial specialization members that are used in a way that requires a definition shall be defined; the definitions of members of the primary template are never used as definitions for members of a class template partial specialization. [...]
The above is stated in the context of partial specializations, but it applies to explicit specializations (as in your case) as well, although the Standard does not say this very clearly.
Also note that you need not only declare all member functions that you want in a specialization, but you need to define them, too (here, the Standard is very clear even about explicit specializations):
(14.7.3/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. [...]
So, indeed, A<int> will only have method2(), and A<float> will only have method1() as member. Furthermore, if you were to introduce method1() in the A<int> specialization as well, it needs not have the same argument types or return type as A<float>::method1().
See #aschepler's answer for possible ways to avoid having to rewrite the template definition for the int case.
#jogojapan's answer explains what the language does. Here's a couple workarounds if you do want to add new members for a specific specialization:
template<typename T>
struct A_Base {
void method1() {}
};
template<typename T>
struct A : public A_Base<T> {};
template<>
struct A<int>
: public A_Base<int>
{
void method2() {}
};
Now A<int> has members method1 and method2, but A<float> has no method2.
OR (if you can modify the primary template)...
#include <type_traits>
template<typename T>
struct A {
void method1() {}
template<int N=0>
auto method2() ->
typename std::enable_if<std::is_same<T, int>::value && N==N>::type
{}
};
The template<int N> and N==N parts make sure std::enable_if has a dependent value and therefore doesn't complain until somebody actually tries to use A<T>::method2 with an incorrect T parameter.
And since this question and answer seem to still be getting attention, a much later edit to add that in C++20, you can simply do:
#include <type_traits>
template<typename T>
struct A {
void method1() {}
void method2() requires std::is_same_v<T, int> {}
};
The specialisation replaces the generic template. So A<int> will only have method2() and, of course, A<double> will only have method1().
Related
I have read What does template's implicit specialization mean? and its answers, but I am still not satisfied that I understand this part of Partial template specialization from cppreference.com:
If the primary member template is explicitly (fully) specialized for a given (implicit) specialization of the enclosing class template, the partial specializations of the member template are ignored for this specialization of the enclosing class template....
template<class T> struct A { //enclosing class template
template<class T2>
struct B {}; //primary member template
template<class T2>
struct B<T2*> {}; // partial specialization of member template
};
template<>
template<class T2>
struct A<short>::B {}; // full specialization of primary member template
// (will ignore the partial)
A<char>::B<int*> abcip; // uses partial specialization T2=int
A<short>::B<int*> absip; // uses full specialization of the primary (ignores partial)
A<char>::B<int> abci; // uses primary
Questions:
The comments say that the line template<> template<classT2> struct A<short>::B {}; is a "full specialization of primary member template". The primary member template is identified in the comments as the structure B. How can the line be a specialization of B when it is A that is being specialized by the substitution of short for class T?
How can the line be a "full" specialization of B when the template parameter T2 is left unspecified?
The comments and the accompanying text indicate that "explicit specialization" and "full specialization" are synonymous terms. If the line of code quoted above is the explicit specialization of B, where is the implicit specialization of A?
A member of a class template can be explicitly specialized even if it is not a template:
template<int I>
struct X {
int f() {return I;}
void g() {}
};
template<>
int X<0>::f() {return -1;}
This is equivalent to specializing the whole class template but with other members duplicated from the relevant primary template or partial specialization:
template<>
struct X<0> {
int f() {return -1;}
void g() {}
};
(Recall that such a spelled-out specialization is under no obligation to declare g at all or as a function.) Since you don’t actually write this, it’s still considered to be an implicit instantiation of X as a whole with the given alteration.
This is why your specialization of A<T>::B provides the template argument for A and not for B; it is replacing the template A<T>::B with another template (that happens to have the same template parameter list). I would say the word “primary” is misleading here: it is the whole template that is replaced, which is why the partial specialization is ignored for A<short> thereafter.
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.
The following code compiles fine:
#include <type_traits>
template <typename T> struct dependent_true : std::true_type { };
template <typename T> struct dependent_false : std::false_type { };
template <bool B = false>
class X { static_assert(dependent_false<X>::value); };
template <>
class X<true> { static_assert(dependent_true<X>::value); };
int main() {
X<true> x;
}
That is, the static_assert in the primary template is not evaluated. On the contrary, if I switch to:
template <bool B = false>
class X { static_assert(dependent_true<X>::value); };
template <>
class X<true> { static_assert(dependent_false<X>::value); };
int main() {
X<false> x;
}
Then, the static assertion in template specialization fails, even if it is not instantiated. I just wonder why. I observed this behavior with GCC 8 and Clang 6 (-std=c++17).
Live demo: https://wandbox.org/permlink/MOWNLnGMgmuDA2Ht
template <> class X<true> {/* ... */}; - is not a template anymore.
[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.
The specialization is just like a regular class. It's not a template, and nothing is dependent. Therefore dependent_false<X>::value is just a constant expression that evaluates immediately to false. So the static assertion is immediately triggered.
Even non-instantiated template parts should be valid C++ code. static_assert(false) makes the program ill-formed. So you have your specialization with static_assert which is known on compile time to be false and your program becomes ill-formed. You have no non-resolved template parameters on your class which is used in static_assert to make compiler wonder; it knows exactly that it is false.
The same goes to if constexpr, you also can't use static_assert with expressions known to be false even if the part where this static_assert is located always gets discarded.
#include <stdio.h>
template<typename T, int N>
class A
{
public:
void func();
};
template<typename T, int N>
void A<int, N>::func()
{
printf("%d\n", N);
}
int main()
{
A<int, 3> a;
a.func();
return 0;
}
When I try to compile this piece of code, g++ gives these errors:
test.cpp:10:22: error: invalid use of incomplete type ‘class A<int, N>’
test.cpp:4:7: error: declaration of ‘class A<int, N>’
I've only managed to compile this when A::func isn't specialized at all and when the function is also specialized for N.
How do I specialize A::func for T and access N (which should be able to be any value), too?
If this was possible, the syntax would have to be
template<int N>
void A<int, N>::func()
{
printf("%d\n", N);
}
I.e., T would not be mentioned in the template parameter list.
But unfortunately, it isn't possible. Individual functions (including member functions) cannot be partially specialized.
From the Standard (in the section about partial class template specializations):
(§14.5.5/2) Each class template partial specialization is a distinct template and definitions shall be provided for the members of a template partial specialization (14.5.5.3).
In your situation, the most direct way to accomplish what you need would therefore be to partially-specialize the entire class template:
template<int N>
class A<int,N>
{
public:
void func();
};
template<int N>
void A<int,N>::func()
{
printf("%d\n",3);
}
Working example of this on Coliru (Of course, the definition of func could be inlined into the class template definition.)
But this might not be optimal when the class template has many other members, since you would have to redefine them all:
(§14.5.5/3) [...] 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. Class template partial specialization members that are used in a way that requires a definition shall be defined; the definitions of members of the primary template are never used as definitions for members of a class template partial specialization. [...]
In some cases it is preferable to declare a separate class template with just this one function as member (possibly a static member, if no access to other members is required – possibly passing members to which access is required as explicit function arguments), and then refer to that from within the actual class template (to avoid having to partially-specialize the entire class template).
What is meant with "deferred instantiation" in C++ templates?
Deferred instantiation is when the template is not instantiated until the corresponding entity is used for the first time. For example, you have a templated function:
template<int Size>
void YourFunction()
{
//does something
}
parameter Size can have any possible value that int can have. Do you automatically have the templated function instantiated for all possible values of Size? No, the template is only instantiated for the values that are actually used as the parameter when the function call first appears in the code:
YourFunction<100>(); //instantiated for 100
I have only heard people use the term "deferred instantiation" to refer to the situation where a class member definition is instantiated only if it is used
template<typename T>
struct A {
void f() {
T a; // invalid if T is void
}
};
A<void> a; // valid!
In this case, A<void> is implicitly instantiated because the compiler needs to know its size (formally, the class type needs to be complete, so an instantiation is triggered). But the instantiation of its member definitions are deferred until they are actually used. This does not only apply to member functions, but also to static data members and nested classes
struct Print {
Print() { std::cout << "hello!"; }
};
template<typename T>
struct A {
static Print print;
};
template<typename T>
Print A<T>::print;
Now even if you implicitly instantiate A<T> the message won't be printed until you explicitly refer to A<T>::print and use it. Explicit instantiation won't defer instantiation of member definitions - so the following will always print the message
template struct A<void>;
There is a trick to trigger instantiation of member definitions for implicit instantiations though: Refer to them in declaration parts of a class' member, like in the following changed class template
template<typename T, T&> struct useit { };
template<typename T>
struct A {
static Print print;
typedef useit<Print, print> useit_type;
};
Now if A<T> is implicitly instantiated the message is printed, because the typedef declaration refers to it.