I just read the wiki article about CRTP, and I'm a little confused about template instantiation.
According to the wiki,
member function bodies (definitions) are not instantiated until long
after their declarations.
I don't quite understand what it means.
Suppose I got a class template:
template <typename T>
class A
{
public:
void foo(T t)
{
//...
};
};
When I instantiate the class template A, does it instantiate the member function foo()?
For example:
//in .cpp file
int main()
{
A<int> a; //question 1
//class template is instantiated here, isn't it?
//What about foo(), is it instantiated too?
a.foo(10); //question 2
//according to the quotation, foo() will not be instantiated until it is used.
//if so, foo() is instantiated right here, not in question 1, right?
}
You seem to be confusing one thing:
Instantiation happens during compilation, not during runtime. Hence you can't say "on which line" a class template or a function template was instantiated.
That said, you're right about the fact that member function templates aren't instantiated together with class templates.
You could observe it in such a case: You have the following files
template.h (defines class A and function A::foo)
a.cpp (uses A)
b.cpp (uses A and A::foo)
Then during compilation of a.cpp, only A would be instantiated. However, during compilation of b.cpp, both would be instantiated.
Because of this, in case A::foo contained some semantically invalid code for a given set of template parameters, you would get compile errors in b.cpp, but not a.cpp.
I hope that clears things up!
With class templates, the rule of thumb is that only those members are instantiated which are actually used.
If you want complete instantiation, C++ offers explicit instantiation (however, usually you don't; the fact that not every bit is fully instantiated means that your template class is even more generic as it lowers the requirements on T, note that syntax checking and lookup of non-dependent types (stuff that is not dependent on T) still happens).
You will find a more complete answer here: Template instantiation details of GCC and MS compilers
Related
Consider this. There is a class Derived that inherits from some instantiation of a heavy templated class Base, and there are many uses of Derived in various source files. So it is reasonable to have only one Derived-specific instantiation of Base.
C++11 allows this via extern template, but the problem here is that I want to type the Derived-specific instantiation of Base only once. Technically it is possible, as Derived can hold an alias for that instantiation, but the question is: will it still force the compiler not to instantiate the template?
Here is the try:
// Base.hpp
template < typename Arg > struct Base { using TheArg = Arg; };
// Derived.hpp
#include "Base.hpp"
struct Derived : Base<int> { };
// The next line will be huge in real-world scenario, so I want to avoid it.
// extern template struct Base<int>;
// Instead I want this.
extern template struct Base<Derived::TheArg>;
// Derived.cpp
#include "Derived.hpp"
template struct Base<Derived::TheArg>;
// Use01.cpp
#include "Derived.hpp"
void use01() { Derived dd; }
The point here is to force Use01.cpp not to instantiate Base<int> and to refer to the explicit instantiation at Derived.cpp instead.
I am compiling with gcc-v9.3 and the questions are:
Does extern template declaration takes effect to all instantiations in the translation unit, or only to those which appear after its declaration?
Will using Derived::TheArg instead of int cause any problems with deferring the instantiation?
Putting the extern template declaration at the end of Use01.cpp and commenting out the explicit instantiation at Derived.cpp makes the compilation to fail, so this gives me some confidence that the extern template declaration doesn't have to appear before any instantiation, so the second question still makes sense.
An explicit instantiation declaration of a specialization of a class template doesn’t prevent instantiating that specialization. After all, you still need to be able to refer to members of the resulting class, which means knowing everything about its layout. What it does do is prevent instantiation of its (non-inline) member functions, so that no code need be emitted for them.
Additionally, an explicit instantiation declaration must precede any source of implicit instantiation to be effective. If you want to name that specialization’s template argument just once, introduce a type alias for it before the explicit instantiation declaration and the definition of Derived.
Recently when I was trying to optimize my include hierarchy I stumbled upon the file a.hpp:
template<class T>
class A
{
using t = typename T::a_t;
};
class B;
extern template class A<B>;
which seems to be ill-formed. In fact it seems as if the extern template statement at the end causes an instantiation of A<B> which causes the compiler to complain about an incomplete type.
My goal would have been to define A<B> in a.cpp:
#include <b.hpp>
template class A<B>;
This way I avoid having to include b.hpp from a.hpp which seems like a good idea to reduce compile time. However it does not work (a.hpp on itself doesn't compile!) Is there a better way of doing this?
Note: Of course I could just not use explicit template instantiation but this is not what I want! I would like to "precompile" A<B> to save compilation time if it were used, but if A<B> is not used I don't want to include b.hpp in every file that uses a.hpp!
The extern template declaration prevents the instantiation of member function bodies, but it forces the instantiation of the class definition, since the compiler needs that anyway, and the class body needs a full definition of the template argument since it accesses its members. I'm afraid that hiding B's body from users of A<B> is not possible.
extern template is an optimization, but it doesn't change the fundamental workings of the instantiation mechanism.
From http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1448.pdf
The extern specifier used to declare an explicit instantiation of a
class template only suppresses explicit instantiations of definitions
of member functions and static data members not previously specialized
in the translation unit containing the declaration.
Thus, if a definition of B is required in A, you cannot use an extern template without knowledge of B. You could of course try to get rid of that requirement. In the given case, you could remove the using t declaration and have a meta function to yield that type:
template<typename T>
struct get_a_t;
template<typename T>
struct get_a_t<A<T>>
{
using type = typename T::a_t;
};
Not sure it that is feasible in your case. As soon as A needs to store a B or a B::a_t, you need B. References and pointers would be OK, though.
The final extern template class A is telling the compiler that there is in some compilation unit a declaration of such template specialization. The compiler goes on and then the linker should complain about not finding the correct class. It is not ill formed; it depends on the use case. You can define in a separate cpp file the template A. This will obviously just reduce a bit the compile time if you compile it over and over. You can do different structures:
one a.hpp with just the class A template.
one b.cpp file with the class B along with its .h file. (is it a template?)
b.cpp includes a.hpp and inside you make an explicite template instantiation template class A; (not with extern).
At this point whenever you need to use that template you can just write
extern template class A;
in your file and link the compiled b.cpp file. If you include the a.hpp file since you still need the template you won't recompile it since you have the extern command.
consider the following code:
//header.h
template<class T>
class A
{
static int x;
};
template<class T>
int A<T>::x = 0;
//source1.cpp
#include "header.h"
void f(){} // dummy function
//main.cpp
#include "header.h"
int main(){}
In this case code compiles perfectly without errors, but if I remove the template qualifier from class
class A
{
static int x;
};
int A::x = 0;
In this case compiler erred with multiple definition of x. Can anybody explain this behavior?
And when the template class's static variable is initialized / instantiated??
Compiler will remove duplicate template instantiations on its own. If you turn your template class into regular one, then its your duty to make sure only one definition of static variable exists (otherwise linker error will appear). Also remember that static data members are not shared between instatiations of templates for different types. With c++11 you can control instatiations on your own using extern templates: using extern template (C++11).
As for the point of instatiation for static members:
14.6.4.1 Point of instantiation [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.
so point of instatiation should be ie. right after main() if you use your type for the first time inside main().
Templates as the name suggest are the the fragments of code that will be used several times for different parameters. For templates the compiler is to ensure if their methods and static fiels definition are linked only ones. So if you create a static field with its default value the compiler is obliged to provide single memory cell (for the same template parameter set) even though the template class header is included several times. Unfortunetly non-template classes you need to be managed by yourself.
As for the second question, I believe the standard does not state when the static fields need to be initialized, each compiler can implement then it in its own manner.
It is necessary to instantiate/initialize static members in cpp files not in headers. Static members are property of class not property of objects, so if you include header file in more cpp files, it looks like you are initializing it more times.
Answer to this question is more complex. Template is not one class. It is instantiating on demand. It means that every different use of template is one standalone "template instance". For example if you use A<int> and A<float> than you will have 2 different classes therefore you would need to initialize A<int>::x and A<float>::x.
For more info see this answer: https://stackoverflow.com/a/607335/1280316
A class (be it a template or not) can (and should) be declared in any compilation unit that referes to it.
A static field initialization does defines a variable, and as such it should exist only in one compilation unit -> that's the reason why you get an error when class A is not a template.
But when you declare a template, nothing is really created untill you instantiate it. As you never instantiate the template, the static field is never defined and you get no error.
If you had two different instantiations in source1.cpp (say A<B>) and main.cpp (say A<C>) all will still be fine : you would get A<B>::x in source1 and A<C>::x in main => two different variables since A<B> and A<C> are different classes.
The case where you instantiate same class in different compilation units is trickier. It should generate an error, but if it did, you could hardly declare special fields in templates. So it is processed as a special case by the compiler as it is explained in this other answer to generate no errors.
Could anyone provide a comparison or specific details of how is template instantiation
handled at compile and/or link time in GCC and MS compilers? Is this process different
in the context of static libraries, shared libraries and executables?
I found this doc about how GCC handles it but I'm not sure if the information
is still referring to the current state of things. Should I use the flags
they suggest there when compiling my libraries e.g. -fno-implicit-templates?
What I know (might not necessarily be correct) is that:
templates will be instantiated when actually used
templates will be instantiated as a result of explicit instantiations
duplicate instantiation is usually handled by folding duplicate instantiations, or by deferring instantiation until link time
Point of instantiation
templates will be instantiated when actually used
Not exactly, but roughly. The precise point of instantiation is a bit subtle, and I delegate you over to the section named Point of instantiation in Vandevoorde's/Josuttis' fine book.
However, compilers do not necessarily implement the POIs correctly: Bug c++/41995: Incorrect point of instantiation for function template
Partial instantiation
templates will be instantiated when actually used
That is partially correct. It is true for function templates, but for class templates, only the member functions that are used are instantiated. The following is well-formed code:
#include <iostream>
template <typename> struct Foo {
void let_me_stay() {
this->is->valid->code. get->off->my->lawn;
}
void fun() { std::cout << "fun()" << std::endl; }
};
int main () {
Foo<void> foo;
foo.fun();
}
let_me_stay() is checked syntactically (and the syntax there is correct), but not semantically (i.e. it is not interpreted).
Two phase lookup
However, only dependent code is interpreted later; clearly, within Foo<>, this is dependent upon the exact template-id with which Foo<> is instantiated, so we postponed error-checking of Foo<>::let_me_alone() until instantiation time.
But if we do not use something that depends on the specific instantiation, the code must be good. Therefore, the following is not well-formed:
$ cat non-dependent.cc
template <typename> struct Foo {
void I_wont_compile() { Mine->is->valid->code. get->off->my->lawn; }
};
int main () {} // note: no single instantiation
Mine is a completely unknown symbol to the compiler, unlike this, for which the compiler could determine it's instance dependency.
The key-point here is that C++ uses a model of two-phase-lookup, where it does checking for non-dependent code in the first phase, and semantic checking for dependent code is done in phase two (and instantiation time) (this is also an often misunderstood or unknown concept, many C++ programmers assume that templates are not parsed at all until instantiation, but that's only myth coming from, ..., Microsoft C++).
Full instantiation of class templates
The definition of Foo<>::let_me_stay() worked because error checking was postponed to later, as for the this pointer, which is dependent. Except when you would have made use of
explicit instantiations
cat > foo.cc
#include <iostream>
template <typename> struct Foo {
void let_me_stay() { this->is->valid->code. get->off->my->lawn; }
void fun() { std::cout << "fun()" << std::endl; }
};
template struct Foo<void>;
int main () {
Foo<void> foo;
foo.fun();
}
g++ foo.cc
error: error: ‘struct Foo<void>’ has no member named ‘is’
Template definitions in different units of translation
When you explicitly instantiate, you instantiate explicitly. And make all symbols visible to the linker, which also means that the template definition may reside in different units of translation:
$ cat A.cc
template <typename> struct Foo {
void fun(); // Note: no definition
};
int main () {
Foo<void>().fun();
}
$ cat B.cc
#include <iostream>
template <typename> struct Foo {
void fun();
};
template <typename T>
void Foo<T>::fun() {
std::cout << "fun!" << std::endl;
} // Note: definition with extern linkage
template struct Foo<void>; // explicit instantiation upon void
$ g++ A.cc B.cc
$ ./a.out
fun!
However, you must explicitly instantiate for all template arguments to be used, otherwise
$ cat A.cc
template <typename> struct Foo {
void fun(); // Note: no definition
};
int main () {
Foo<float>().fun();
}
$ g++ A.cc B.cc
undefined reference to `Foo<float>::fun()'
Small note about two-phase lookup: Whether a compiler actually implements two-phase lookup is not dictated by the standard. To be conformant, however, it should work as if it did (just like addition or multiplication do not necessarily have to be performed using addition or multiplication CPU instructions.
Edit: It turns out that what I wrote below is contrary to the C++ standard. It is true for Visual C++, but false for compilers that use "two-phase name lookup".
As far as I know, what you say is correct. Templates will be instantiated when actually used (including when declared as a member of another type, but not when mentioned in a function declaration (that does not have a body)) or as a result of explicit instantiations.
A problem with templates is that if you use the same template (e.g. vector) in several different compilation units (.cpp files), the compiler repeats the work of instantiating the template in each .cpp file, thus slowing down compilation. IIRC, GCC has some (non-standard?) mechanism that can be used to avoid this (but I don't use GCC). But Visual C++ always repeats this work, unless you use explicit template instantiation in a precompiled header (but even this will slow down your compile, since a larger PCH file takes longer to load.) Afterward, the linker then eliminates the duplicates. Note: a comment below linked to a page which tells us that not all compilers operate this way. Some compilers defer function instantiation until link time, which should be more efficient.
A template is not fully instantiated when it is first used. In particular, functions in the template are not instantiated until they are actually called. You can easily verify this by adding a nonsense function to a template you are actively using:
void Test() { fdsh "s.w" = 6; wtf? }
You won't get an error unless you instantiate the template explicitly, or try to call the function.
I expect static libraries (and object files) will store the object code of all templates that were instantiated. But if your program has a certain static library as a dependency, you can't actually call the template functions that were already instantiated therein, at least not in VC++, which always requires the source code (with function bodies) of a template class in order to call functions in it.
I don't think it's possible to call a template function in a shared library (when you don't have the source code of the template function you want to call).
I heard C++ templates wont generate errors until they are used. Is it true ? Can someone explain me how they work ?
Templates follow two phase compilation model.
struct X{
private:
void f(){}
};
template<class T> void f(T t){
int; // gives error in phase 1 (even if f(x) call is commented in main)
t.f(); // gives error only when instantiated with T = X, as x.f() is private, in phase 2
}
int main(){
X x;
f(x);
}
They generate compiler errors when they are compiled. They are compiled separately for each actual parameter passed as the template argument(s) (this is unlike Java Generics), e.g., if I have:
template <typename T> class foo { ... }
and
int main() {
foo<char> c;
foo<int> i ;
}
the template foo gets compiled twice, once for chars, once for ints.
If you never (directly or indirectly) instantiated or used template foo, it wouldn't be compiled and you'd not see any compiler errors.
Once compiled, they're just "normal" C++ code, and like any code, can generate runtime errors.
From here,
From the point of view of the
compiler, templates are not normal
functions or classes. They are
compiled on demand, meaning that the
code of a template function is not
compiled until an instantiation with
specific template arguments is
required. At that moment, when an
instantiation is required, the
compiler generates a function
specifically for those arguments from
the template.
Hope it helps..
Conceptually, at the highest level
template <Type value, class Y, ...>
...fn-or-class...
may be usefully compared to
#define FN_OR_CLASS(VALUE, TYPE_Y, ...) \
...fn-or-class...
Both basically wait until called/instantiated then substitute the specified types and values to produce tailored code with full compile-time optimisation for those values. But, templates differ from #defines in that they're proper compile-stage constructs that can be enclosed in namespaces, must satisfy the lexer, and not all of a class template is generated when the first instantiation is seen - rather, functions are generated on an as-needed basis.
When the compiler first encounters a template, it does a rough check that the template's content could make sense for some hypothetical instantiation. Later, when it encounters a specific instantiation, then for class templates only the functions that are used are further checked to make sure they can be compiled with the specific parameters in use. This does mean that a class template can appear - for some limited usage - to support instantiation with specific parameters, but if you start using some other functions in the template API then suddenly you can find that it can't be compiled with that presumed-suitable parameter... can force you to redesign your usage rather late in the day. That is one of the reasons that C++0x had planned to introduce Concepts: they elegantly allow templates to check that parameters meet all the template's expectations - if they allow any instantiation, then the user can assume that the full API of the template can be used.
template <class T>
struct X
{
void f() { }
void g() { T::whatever(); } // only error if g() called w/o T::whatever
};
int main()
{
X<int> x;
x.f();
// x.g(); // would cause an error as int::whatever() doesn't exist...
}
The SFINAE (substitution failure is not an error) technique can then allow the compiler to select between multiple nearly-matching functions based on the actual instantiating template parameters. This can be used to implement basic compile-time introspection, such as "does this class have a member function fn(int)?".