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.
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.
Consider the below code:
#include <iostream>
template<typename T>
struct Test{
template<typename U>
static U value;
};
template<typename T>
template<typename U>
U Test<T>::value = U{};
//#1
int main(){
auto d = Test<int>::value<int>;
}
//#2
The [temp.point] section in the standard covers the most case of where the point of instantiation shall place. However I think it's unclear about static data member template, due to:
temp.point#1
For a function template specialization, a member function template specialization, or a specialization for a member function or static data member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization and the context from which it is referenced depends on a template parameter, the point of instantiation of the specialization is the point of instantiation of the enclosing specialization. Otherwise, the point of instantiation for such a specialization immediately follows the namespace scope declaration or definition that refers to the specialization.
temp.point#4
For a class template specialization, a class member template specialization, or a specialization for a class member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization, if the context from which the specialization is referenced depends on a template parameter, and if the specialization is not instantiated previous to the instantiation of the enclosing template, the point of instantiation is immediately before the point of instantiation of the enclosing template. Otherwise, the point of instantiation for such a specialization immediately precedes the namespace scope declaration or definition that refers to the specialization.
Two paragraphs all respectively cover the case they mentioned, they are a specialization for static data member of a class template and a class member template specialization, So, the specialization for static data member template could be called a specialization for static data member of a class template or a class member template specialization? I prefer to consider it as a class member template specialization, My reason is in the first paragraph, it has mentioned a member function template specialization, that implies if A is a specialization for X template, it would call it a X template specialization, however It's just my inference.
In the section of [temp.static], it implies that a static data member and static data member template are collectively called static data member of class or class template.
temp.static#1
A definition for a static data member or static data member template may be provided in a namespace scope enclosing the definition of the static member's class template.
[Note: A specialization of a static data member template is a static data member. A specialization of a member function template is a member function. A specialization of a member class template is a nested class. — end note]
Now, the wording makes the question more unclear. So according to the above rules, Is the point of instantiation for Test<int>::value<int> is at #2 or #1?
If the POI of Test<int>::value<int> is at #2, then it will be considered as a specialization for static data member of a class template, otherwise if it's at #1, then it will be considered as a class member template specialization, I don't know which the position is correct. If I miss something, please correct me.
You may be confusing instantiation/specialization
template<typename T>
template<typename U>
U Test< T >::value = 88; // <- this is not specialization
template<>
template<>
int Test< int >::value<int> = 98; // <- this is specialization
Run this code https://godbolt.org/z/h434eG, take a look at the order of the numbers on the output, then uncomment the block with a specialization and run again.
The point of Cleiton Santoia Silva is that there is no explicit member template specialisation.
But if you read temp.inst#3:
Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated side effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.
We still get a specialization which is triggered by the template usage in main. I would say to "virtual specialization", because it is not visible in the code. This results exaclty like if there would be an explicit specialization.
But the question is where would the compiler write this specialization - which is defined in [temp.point]. But by which paragraph? If you read carefully paragraph 4 you can see it has an additional condition (the otherwise is related to the inner / second if):
...if the specialization is implicitly instantiated because it is
referenced from within another template specialization, if the context from which the specialization is
Is the member function template referenced by the class template "Test"? No, it is only referenced inside main. So, we don't need to look at this paragraph.
But let us look at the first paragraph. There we have nearly the same condition just without "if" but "and":
For a function template specialization, a member function template specialization, or a specialization for a member function or static data member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization and the context from
Because the condition is not true we need to look at the "else case":
... Otherwise, the point of instantiation for such a specialization immediately follows the namespace scope declaration or definition that refers to the specialization.
This sentence is somehow misleading. What is a namespace scope declaration (I found no definition in the standard)? And which definition is meant here? Your interpretation was that the definition is meant where the template instanciation occured (main). But I don't think so. I Think definition of the template is meant.
So to answer your question: it should be before main (after main would make the program "ill-formed"). But you are right the wording should be improved there.
Btw:
You can have a "look inside a C++ compiler" by using cppinsights (here). Unfortunately it seems to work not correctly (in that case) for the implicit global namespace scope. Here you can see where the specializations are "practically" instantiated.
Old Answer
Cleiton Santoia Silva is totally right. Your source code shows just a static template member declaration and a static template member definition. It is no specialization.
Look here
The template instation happens here:
#include <iostream>
template<typename T>
struct Test{
template<typename U>
static U value; //this is a static member template declaration
};
template<typename T>
template<typename U>
U Test<T>::value = U{}; //this is a static member template definition
//this is a partial specialization of a template member variable
template<>
template<typename U>
U Test<char>::value = 42;
//this is a full specialization of a template member variable
template<>
template<>
int Test<int>::value<int> = 22;
int main()
{
auto d = Test<int> //<- here is Test<int> implicitly instantiated
::value<int>; //<- here is the member template ::Test<int>::value<int> implicitly instantiated
std::cout << Test<char>::value<int> << "\n"; //this prints 42
std::cout << Test<int>::value<int> << "\n"; //this prints 22
std::cout << Test<bool>::value<bool> << "\n"; //this prints 0
}
If you would write this - your program becomes ill-formed:
#include <iostream>
template<typename T>
struct Test{
template<typename U>
static U value; //this is a static member template declaration
};
template<typename T>
template<typename U>
U Test<T>::value = U{}; //this is a static member template definition
int main()
{
auto d = Test<int> //<- here is Test<int> instantiated
::value<int>; //<- here is the member template instantiated
std::cout << Test<char>::value<int> << "\n"; //this prints 42
std::cout << Test<int>::value<int> << "\n"; //this prints 22
std::cout << Test<bool>::value<bool> << "\n"; //this prints 0
}
//this is a partial specialization of a template member variable
template<>
template<typename U>
U Test<char>::value = 42;
//this is a full specialization of a template member variable
template<>
template<>
int Test<int>::value<int> = 22;
But this would be fine. Non inline static member definitions must defined in cpp files to not violate ODR.
But like with all templates - every template definition must be available in all translations units. This is reason why such a definition is usually definied in a header:
#include <iostream>
template<typename T>
struct Test{
template<typename U>
static U value; //this is a static member template declaration
};
//this is a partial specialization of a template member variable
template<>
template<typename U>
U Test<char>::value = 42;
//this is a full specialization of a template member variable
template<>
template<>
int Test<int>::value<int> = 22;
int main()
{
auto d = Test<int> //<- here is Test<int> implicitly instantiated
::value<int>; //<- here is the member template ::Test<int>::value<int> implicitly instantiated
std::cout << Test<char>::value<int> << "\n"; //this prints 42
std::cout << Test<int>::value<int> << "\n"; //this prints 22
std::cout << Test<bool>::value<bool> << "\n"; //this prints 0
}
template<typename T>
template<typename U>
U Test<T>::value = U{}; //this is a static member template definition
The following bit of code fails to compile on gcc 4.5.3
struct Frobnigator
{
template<typename T>
void foo();
template<typename T>
void bar();
};
template<typename T>
void Frobnigator::bar()
{
}
template<typename T>
void Frobnigator::foo()
{
bar<T>();
}
template<> // error
void Frobnigator::foo<bool>()
{
bar<bool>();
}
template<>
void Frobnigator::bar<bool>()
{
}
int main()
{
}
Error message: specialization of ‘void Frobnigator::bar() [with T = bool]’ after instantiation. I finally resolved this problem by having the specialization of Frobnigator::bar<bool>() appear before Frobnigator::foo<bool>(). Clearly the order in which the methods appear matter.
Why then is the following lite version of the above code, in which the the specialization of bar appears after the generic version, valid ?
struct Frobnigator
{
template<typename T>
void foo();
};
template<typename T>
void Frobnigator::bar()
{
}
template<>
void Frobnigator::bar<bool>()
{
}
int main()
{
}
Your first code is not correct by standard.
n3376 14.7.3/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.
In your case - implicit instantiation of bar function with type bool is required by its usage in foo<bool>, before explicit specialization declaration.
Clearly the order in which the methods appear matter.
Indeed; as is usually the case in C++, you can't use something before it's declared, and this applies to explicit template specialisations as well as most other things.
Using bar<bool> (by calling it from foo<bool>) without a previous declaration of an explicit specialisation causes that specialisation to be instantiated from the generic template, if it hasn't already been. You'll need at least a declaration of the explicit specialisation to prevent that.
Why is this the case, considering that the specialization of bar appears after the generic version in the following lite version of the above code
The second example differs by not instantiating foo<bool> at all. The issue isn't that the specialisation is declared after the generic template (which must be the case), but that it's declared after that specialisation has already been instantiated.
Consider the following header file:
// Foo.h
class Foo {
public: template <typename T> void read(T& value);
};
It seems that assigning a pointer to Foo::read<T> in the constructor of a class, of which variable is then declared, cause instantiation:
// Foo.cc
#include "Foo.h"
template <typename T>
void Foo::read(T& value) { /* do something */ }
template <typename T> struct Bar {
Bar<T>() { void (Foo::*funPtr)(T&) = &Foo::read<T>; }
};
static Bar<int > bar1;
static Bar<long > bar2;
static Bar<float> bar3;
Is this solution reliable / portable / standard-conformant? (It works at least with Intel and GNU compilers.)
If you wonder why not to simply use template Foo::read<int>(int&); see this question.
Yes, your solution is portable. Here is a different way
template <typename T, T> struct user { };
template <typename T> struct Bar {
typedef user< void (Foo::*)(T&), &Foo::read<T> > user_type;
};
Now whenever Bar<T> is implicitly instantiated, it will implicitly instanitate Foo::read<T>. No object needs to be created.
14.7.1 is where it's at. /2 says:
Unless a function template
specialization has been explicitly
instantiated or explicitly
specialized, the function template
specialization is implicitly
instantiated when the specialization
is referenced in a context that
requires a function definition to
exist.
Just like calling a function, taking a member function pointer requires that the function is defined in the program (perhaps in another TU). I believe that's what "requires a function definition to exist" means, so this is what causes the instantiation.
There's also /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.
So the fact that GCC and Intel instantiate it suggests that everyone else should, since that which is not required is forbidden. Assuming everyone conforms, of course.
When objects for Bar<type> are declared with actual types then definitely, Yes; it will instantiate Foo::read<type>(). However, it will be limited only to that function (say Foo::write<type>() will not be instantiated).
In other way, if you try something like this:
template<typename T>
struct X
{
Bar<T> b1; // this is required but not sufficient to instantiate Foo::read<T>()
};
Then Foo::read<int>() will not be instantiated until you declare X<int>.
Edit:
In above example, directly declaring Bar<int> b1; (int instead of T) inside X is also NOT sufficient. Its containing type X<> has to be instantiated with actual (i.e. non-template) type.
This is the statement from ISO C++ Standard 14.6.4.1 Point of instantiation
For a function template specialization, a member function template
specialization, or a specialization for a member function or static
data member of a class template, if the specialization is implicitly
instantiated because it is referenced from within another template
specialization and the context from which it is referenced depends on a
template parameter, the point of instantiation of the specialization is
the point of instantiation of the enclosing specialization. Otherwise,
the point of instantiation for such a specialization immediately follows
the namespace scope declaration or definition that refers to the
specialization.
If a function template or member function of a class template is called in
a way which uses the definition of a default argument of that function
template or member function, the point of instantiation of the default
argument is the point of instantiation of the function template or member
function specialization.
For a class template specialization, a class member template specialization,
or a specialization for a class member of a class template, if the
specialization is implicitly instantiated because it is referenced from
within another template specialization, if the context from which the
specialization is referenced depends on a template parameter, and if the
specialization is not instantiated previous to the instantiation of the
enclosing template, the point of instantiation is immediately before the
point of instantiation of the enclosing template. Otherwise, the point of
instantiation for such a specialization immediately precedes the
namespace scope declaration or definition that refers to the specialization.
I am unable to write a programs for this whole section. I am trying to write a programs for this section from yesterday.
Can any one provide me a code for this sections to understand.
Please, normally ..I tried to ask a 1 or more points. In any section. But here iam unable to understand a single point in this section.
So, kindly can any one provide me a code(programs) for this sections to understand.
I find this quite mind-screwing, and the committee has more such fun. So I think it's likely I have some errors in the below. So please read it with care :)
Third paragraph
For a class template specialization, a class member template specialization, or a specialization for a class member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization, if the context from which the specialization is referenced depends on a template parameter, and if the specialization is not instantiated previous to the instantiation of the enclosing template, the point of instantiation is immediately before the point of instantiation of the enclosing template.
In other words, if a class template or a nested class of a class template is instantiated, and the context that causes that instantiation depends on a template parameter, the template/nested class is instantiated immediately before the point of instantiation of the template that refers to it.
The context in the other specialization can either depend on template parameters, which is the case for primary templates, partial specializations and members of a class template, or it does not depend on template parameters, which is the case for references from within explicit specializations.
Otherwise [i.e. the context is nondependent], the point of
instantiation for such a specialization immediately precedes the namespace scope declaration or definition that refers to the specialization.
This distinction is important. Consider what would happen if the point of instantiation for specializations from dependent contexts would preceede immediately to the namespace scope declaration or definition that refers to it
template<typename T, int N>
struct A {
typedef typename A<T, N-1>::type *type;
};
template<typename T>
struct A<T, 0> {
typedef T type;
};
typedef A<int, 2>::type ptr;
This template is supposed to add N pointer declarators. So A<int, 2> is int** for example.
The context around typedef A<int, 2>::type is non-dependent, so A<int, 2> is instantiated before the typedef declaration.
Within A<int, 2>, we have A<int, N-1>::type, which appears in a dependent context and which references A<int, 1>::type. So the Standard requires us to instantiate A<int, 1> at the same point we instantiated A<int, 2>.
If we would instantiate this immediately before the namespace scope declaration that referred to it (before the primary template definition), we would not notice the partial specialization A<T, 0> when processing `A<int, N-1>::type within A<int, 1> because we would instantiate A<int, 1> before that specialization.
Second paragraph
This is just so that names looked up in default arguments are consistent with names looked up in the rest of the function that they are used for (i.e their POI is the same as the POI of their function template / member function of class template).
First paragraph
This is basically the same as the third paragraph. However, function templates are instantiated after the entity that refer to them so that recursive uses are possible, like in the following example. In contrast, class templates are instantiated before the entity that refer to them because the entity required that class type to be complete. If the class type's POI would be after that entity, the class type would still be non-existent.
template<typename T>
void f(T);
template<typename T>
struct A {
void g() {
f(0);
}
void h() { /* do a dance */ }
};
template<typename T>
void f(T t) {
A<T> a;
a.h();
}
void g() {
A<int> a;
a.g();
}
If f would be instantiated before A<int>, then it could not access a.h() because at that point it did not exist yet. Therefor, function templates are instantiated after the entity that refer to them, and class templates are instantiated before the entity that refer to them.
Request some one to correct my understanding...
I think the code below illustrates what 1 and 2 mean (from what I have understood):
template<class T> void f1(T t){cout << 0;}
template<class T> void f2(T t, void (*p)(int) = f1){
(*p)(0);
}
void f(double d){cout << 1;}
template<class T> void g(T t){
f1(t); // this is the interesting call.
}
void f1(int t){cout << 2;}
int main(){
g(2);
f2(2);
} // POI for f1(t), Also POI for f2(2)
Consider the call g(2). At the POI, there are basically three overloads (viable) that are visible:
function template
f(int)
f(double).
The call however routs to 'f(int)' as this is the best match.
In the same way, the POI for 'f2(2)' is the closing brace of main. The default argument 'f1' is once again looked up from this POI and resolves to 'f1(int)' which is the best match of all the three overloads available.
Thanks #litb. Revised after #litb corrected my understanding:
double f1(double d){cout << 1; return 0.0;}
template<class T> void f2(T t1, T t2 = f1(T())){}
template<class T> void g(T t){
f1(t); // this is the interesting call.
}
struct A{
friend A f1(A const &){cout << 2; return A();}
};
int main(){
g(A()); // 'f1(t)' resolves to friend function declaration
f2(A()); // The call to 'f1' in default argument also resolves to friend
// function declaration
// This is because for non dependent names, only ADL is performed
// at POI which is at closing brace of main.
} // POI for f1(t), Also POI for f2(2) in that order
Remember that in both the above calls, there are two overloads that are candidates. The namspace function 'f1(double)' and the friend function 'f1' declaration (found due to ADL). Since this is the only viable function, the calls resolve to the friend declaration 'f1'.
I think Point 3 means this:
template<class A> struct T{
T(int x = 0){}
};
template<class A> struct U{
U():t(f(A())){}
T<A> t;
}; // POI of 'gt' instantiation
T<int> gt(f(2)); // At this point 'f' is not found, hence error
int f(int x){return x;}
int main(){
U<int> u;
} // There are 2 POIs here 'U<int>::T<int>' and 'U<int>' and in that order
// Therefore 'f' is visible from here.