Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template instantiation details of GCC and MS compilers

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
like image 773
celavek Avatar asked Aug 24 '11 21:08

celavek


People also ask

What is instantiation of a template?

The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation to handle a specific set of template arguments is called a specialization.

How do I instantiate a template?

To instantiate a template class explicitly, follow the template keyword by a declaration (not definition) for the class, with the class identifier followed by the template arguments. template class Array<char>; template class String<19>; When you explicitly instantiate a class, all of its members are also instantiated.

Is it necessary to instantiate a template?

In order for any code to appear, a template must be instantiated: the template arguments must be provided so that the compiler can generate an actual class (or function, from a function template).

What is a template compiler?

Template compilation requires the C++ compiler to do more than traditional UNIX compilers have done. The C++ compiler must generate object code for template instances on an as-needed basis. It might share template instances among separate compilations using a template repository.


1 Answers


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.

like image 61
Sebastian Mach Avatar answered Sep 27 '22 23:09

Sebastian Mach