About creating a GCC and MS compiler template

Can someone provide a comparison or specific information on how the instantiated template is processed when compiling 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 document on how GCC handles it, but I'm not sure if the information is still relevant to the current state of things. Should I use the flags they offer there when compiling my libraries, for example. -fno-implicit-templates?

What I know (maybe not necessarily right) is this:

  • templates will be created upon actual use
  • templates will be created as a result of explicit instances
  • instance duplication is usually handled by folding duplicate instances or by deferring instance creation until link time
+41
c ++ gcc compiler-construction visual-studio templates
Aug 24 2018-11-21T00:
source share
2 answers



Instant point

templates will be created upon actual use

Not really, but rude. The exact instantiation point is a little subtle, and I pass you to the section called The Creation Point in the wonderful book of Vandevoord / Josuttis.

However, compilers do not necessarily implement the POI correctly: C ++ / 41995 error: Invalid instantiation point for function template




Partial Instance

templates will be created upon actual use

This is partially correct. This is true for function templates, but only those member functions are instantiated for class templates. The following is the correct 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() checked syntactically (and the syntax is correct there), but not semantically (i.e. it is not interpreted).


Biphasic search

However, only dependent code is interpreted later; it is clear that inside Foo<> , this depends on the exact identifier of the template with which Foo<> , so we deferred the error checking Foo<>::let_me_alone() until the instance was created.

But if we do not use something that depends on a specific instance, the code should be good. Therefore, not :

 $ 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 character to the compiler, unlike this , for which the compiler could determine its instance dependency.

The key point here is that C ++ uses a two-phase search model, where it checks for independent code in the first phase and the semantic verification of the dependent code is performed in the second phase (and the instant of creation) (this is also often a misunderstood or unknown concept, many programmers C ++ suggests that the templates are not processed at all until the instance is created, but this is only a myth coming from, ..., Microsoft C ++).


Full implementation of class templates

The definition of Foo<>::let_me_stay() worked because error checking was deferred to a later version, like the this pointer, which depends. Except when you used

explicit instances

 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 translation units

When you explicitly create an instance, you create the instance explicitly. And make all the characters visible to the linker, which also means that the template definition can be in different translation units:

 $ 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 create an instance for all template arguments, 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()' 



A small note about two-phase search: whether the compiler really implements two-phase search is not dictated by the standard. However, to be compatible, it must work as if it were being executed (just like adding or multiplying does not have to be done using CPU instructions or adding or multiplying.

+49
Aug 30 2018-11-11T00:
source share

Change It turns out that what I wrote below is contrary to the C ++ standard. This is true for Visual C ++, but false for compilers that use "two-phase name lookup."

As far as I know, you are speaking correctly. Templates will be created upon actual use (including if declared as a member of another type, but is not mentioned in the function declaration (which does not have a body)) or as a result of explicit instances.

The problem with templates is that if you use the same template (for example, a vector) in several different compilation units (.cpp files), the compiler repeats the work of creating a template in each .cpp file, which slows down the compilation. IIRC, GCC has some (non-standard?) Mechanism that can be used to avoid this (but I do not 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 compiler, since a larger PCH file takes longer to load.) Then the linker then removes the duplicates. Note : the comment below is related to a page that says that not all compilers work this way. Some compilers delay the instantiation function until connection time, which should be more efficient.

The template is not fully created when it is first used. In particular, functions in the template are not created until they are actually called. You can easily verify this by adding a meaningless function to the template that you are actively using:

 void Test() { fdsh "sw" = 6; wtf? } 

You will not receive an error message unless you explicitly create an instance of the template or try to call a function.

I expect static libraries (and object files) to store the object code of all the templates created. But if your program has a certain static library as a dependency, you can’t actually call the template functions that were already created in it, at least not in VC ++, which always requires the source code (with functions) of the template class in to call functions in it.

I don’t think you can call a template function in a shared library (when you don’t have the source code of the template function you want to call).

-2
Aug 26 2018-11-21T00:
source share



All Articles