Consider the following example:
template <typename T>
class A {
public:
void f() {
cout << "A::f()\n";
}
};
template<>
class A<int> {
};
template<typename T>
class B: public A<T> {
public:
void g() {
cout << "B::g()\n";
A<T>::f();
}
};
int main() {
B<int> b; // (1)
b.g(); // (2)
return 0;
}
Obviously the call to A::f() inside B::g() will fail for int template type. My question is at what point does the call fail? At (1) or (2)? I thought it should be (1) because at that point the compiler creates a new class with the template type int and compiles it. That compilation should fail in f() correct?
It will fail at (2), and this is guaranteed by the standard. In section 14.7.1/1, it says instantiating a template class does not instantiate it's members definitions. That will only happen once the member is used.
If you remove (2) from the code, it will compile.
14.7.1/1 excerpt:
The implicit instantiation of a class template specialization causes the implicit
instantiation of the declarations, but not of the definitions or default arguments, of the class member functions, member classes, static data members and member templates; and it causes the implicit instantiation of the definitions of member anonymous unions.
Emphasis mine.
Visual Studio's diagnosis is misleading. It will say see reference to class template instantiation 'B<T>' being compiled. What it means is not "I'm failing at the instantiation of B<T>", but "I'm failing at instantiating a member of the class B<T>"
It fails at 2). Member function of templates are instantiated when called.
More precisely: When a class template is instantiated, the declaration of its member functions are instantiated, but not their definition. The definition is instantiated when the function is used.
Related
[dcl.spec.auto]/14 states [emphasis mine]:
An explicit instantiation declaration does not cause the instantiation of an entity declared using a placeholder type, but it also does not prevent that entity from being instantiated as needed to determine its type. [ Example:
template <typename T> auto f(T t) { return t; }
extern template auto f(int); // does not instantiate f<int>
int (*p)(int) = f; // instantiates f<int> to determine its return type, but an explicit
// instantiation definition is still required somewhere in the program
— end example ]
and [temp.explicit]/11 states [emphasis mine]:
An entity that is the subject of an explicit instantiation declaration and that is also used in a way that would otherwise cause an implicit instantiation in the translation unit shall be the subject of an explicit instantiation definition somewhere in the program; otherwise the program is ill-formed, no diagnostic required.
Now, consider the following program:
template <class T>
struct Foo {
static const auto& foo() { static T t; return t; }
};
// explicit instantiation declarations
extern template const auto& Foo<void>::foo();
extern template const auto& Foo<int>::foo();
int main() {}
This is well-formed; [temp.explicit]/11 does not apply as neither member function of class template specialization entities Foo<void>::foo() nor Foo<int>::foo() are used in a way that would otherwise cause an implicit instantiation, as per [dcl.spec.auto]/14(1).
Now, consider if we defined a friend function at its friend declaration in the class template Foo:
template <class T>
struct Foo {
static const auto& foo() { static T t; return t; }
friend void bar() { }
};
void bar();
If any more than one specialization of Foo is instantiated in the same translation unit, [basic.def.odr]/1 will be violated:
No translation unit shall contain more than one definition of any variable, function, class type, enumeration type, or template.
as the friend bar() would be re-defined(2) for each specialization that is instantiated.
According to the argument above, the explicit instantiation declarations of the two member function (of class template) specializations should not lead to any instantiation of the associated class template (as per [dcl.spec.auto]/14), meaning the following program should also arguably be well-formed:
template <class T>
struct Foo {
static const auto& foo() { static T t; return t; }
friend void bar() { }
};
void bar();
extern template const auto& Foo<void>::foo();
extern template const auto& Foo<int>::foo();
int main() {}
However, both Clang (10.0.0) and GCC (10.1.0) rejects the program (C++14, C++17, C++2a) with a "redefinition of void bar()” error:
Clang
error: redefinition of bar
note: in instantiation of template class Foo<int> requested here:
extern template const auto& Foo<int>::foo();
GCC
In instantiation of struct Foo<int>:
error: redefinition of void bar()
But I never requested (or, afaict, used these specializations in a way such that) the Foo<int> or Foo<void> specializations (are) to be instantiated.
Thus to the question:
Is the program (with the friend) above well-formed, or are the compilers correct to instantiate the class template specializations and subsequently reject the program?
(1) Note the the same question (and compiler behaviour) applies even if foo() is not declared using a placeholder type, but then we would not be able to fall back on the explicitness of [dcl.spec.auto]/14, but we may not need to.
(2) As friends defined at their friend declaration are inline, we may actually instantiate different specializations in different translation units and still respect ODR, but this is not relevant in this discussion.
The argument that the class template must be instantiated is that declaration matching may need to know things about the class that plainly require instantiation. Consider the simplified example
template<class T>
struct A {void f(T) {}};
extern template void A<int>::f(int);
To know whether the member function exists, we must instantiate the declaration in the class template, and we can’t do that in general without instantiating the whole class: the parameter type could depend on any other declarations in the class template, and we might need to consider multiple overloads or even do template argument deduction to decide which f is meant. One can argue that instantiation should happen only if one of these situations actually pertains, which strays into CWG2 territory (where instantiation is obviously impossible), but the idea is that instantiation is necessary in principle to decide about such questions because we simply don’t try examining the template itself first.
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.
#include <iostream>
template<class T> struct A {
enum E : T;
};
template<class T> enum A<T>::E : T { eT };
template<> enum A<char>::E : char { //#1
echar
};
int main(){
}
Consider the above code which is mentioned in temp.expl.spec#6, it's a typically ill-formed code. The rule says:
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.
At the point #1, where the specialization A<char> will cause implicit instantiation
As a contrast:
#include <iostream>
template<class T> struct A {
struct Test;
};
template<typename T>
struct A<T>::Test{
};
template<>
struct A<int>::Test{ //#2
int c;
};
int main(){
}
Consider this code, At the point #2, where the specialization A<int> also cause implicit instantiation, The difference of the implicit instantiation between such two codes is said as the following:
temp.inst#2
The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions, default arguments, or noexcept-specifiers of the class member functions, member classes, scoped member enumerations, static data members, member templates, and friends; and it causes the implicit instantiation of the definitions of unscoped member enumerations and member anonymous unions. However, for the purpose of determining whether an instantiated redeclaration is valid according to [basic.def.odr] and [class.mem], a declaration that corresponds to a definition in the template is considered to be a definition.
Because in the first code, the member enumeration is unscoped, hence the implicit instantiation of A<char> will also implicit instantiated the definition for enum E. As a contrast, in the second, Test is a member class, hence the implicit instantiation of specialization A<int> will only cause implicit instantiation of the declaration for member class Test rather than definition.
As a variant case of the first code:
#include <iostream>
template<class T> struct A {
enum E : T;
};
template<> enum A<char>::E : char {
echar
};
template<> enum A<int>::E : int { //#1
echar
};
int main(){
}
The difference from the first code is that there's no definition for member enumeration E of its enclosing primary class template, within the primary class template A, it's just a declaration.
So, I think the rule in [temp.expl.spec#6] is not clear. As these above codes shown, in each case, the specialization of primary class template all cause the implicit instantiation for class member, The distinction is one expect the implicit instantiation of declaration , the other is definition.
So, I think modified the rule as the following:
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 of the definition that instantiated from the definition for the corresponding entity, in every translation unit in which such a use occurs; no diagnostic is required.
It will be conform the observable result. If I miss something, please correct me.
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.
I just found that when it comes to templates this code compiles in g++ 3.4.2 and works unless m() is not called:
template <typename T>
class C
{
T e;
public:
C(): e(0) {};
void m()
{
e = 0;
};
};
Now one may create and use instance
C<const int> c;
Until c.m() is not called there are no compile errors but is this legal?
Yes, this is legal. The template specification is that until a method is instantiated, it doesn't exist and therefor is not checked by the compiler. Here's the relevant bit from the spec:
14.7.1 - Implicit instantiation
-9- An implementation shall not implicitly instantiate a function
template, a member template, a
non-virtual member function, a member
class or a static data member of a
class template that does not require
instantiation.