开发者

Meaning of 'instantiation' with respect to templates

开发者 https://www.devze.com 2023-04-02 05:02 出处:网络
Note that code is instantiated only for member functions that are called. For class templates, member functions are instantiat开发者_开发问答ed only when they are used.

Note that code is instantiated only for member functions that are called. For class templates, member functions are instantiat开发者_开发问答ed only when they are used.

The above quote is from the book: C++ Templates by Addison Wesley.

I want to understand the meaning of the jargon "code is instantiated". Does it mean that only a particular memory is reserved, or only that code is compiled or something else?


This is a quite interesting question that should be done in the wider context of how templates are processed by the compiler. Basically templates are code patterns from which the compiler generates classes of functions. A template can be used to generate anything from no code at all (if never used) to an indefinite number of instantiations.

Templates are not directly compiled into any short of entity that is later used with different arguments (that is true in C# generics, but not C++), but rather the code is parsed by the compiler and maintained in memory in case it is later use while processing the current translation unit. That is, the compiler processes the template (template in italics is used in the english form of a pattern from which to create things, not the precise C++ meaning) from which it will create the code (classes or functions) when needed. Instantiation is the process by which the compiler determines that a particular template is used with a particular set of arguments and performs argument substitution on the template to generate the class or function to compile and the final compilation into binary code of the template.

There are two types of template instantiations, implicit and explicit, and the quote you refer to is about implicit template instantiations. I will start with explicit template instantiation just because it is simpler though. When you explicitly instantiate a template (google for the syntax) you tell the compiler that you want code generated from that template applied to the particular arguments that you provide. In the case of a class-template, that forces the instantiation of all of the member functions, which basically means that the compiler will substitute types and compile the result of that into binary objects.

Implicit instantiation, on the other hand, is performed on demand. When you use a class template, the bits and pieces that are actually used get generated from the template and compiled into the translation unit. If you create a variable definition std::vector<int> v;, the compiler will apply the type int (and the defaulted type std::allocator<int>) to the template std::vector and create a type std::vector<int>, but in doing so, it does not compile all of the member functions, but only those needed, which in this case it would be the default constructor std::vector<int>::vector(), and the destructor std::vector<int>::~vector(). The rest of the methods do not get compiled and there will be no code in the binary for them.

There are a few reasons for not instantiating all of the member functions, and the reasons range in complexity from simple to deep in language details. For some of the simpler ones, you can consider performance of compilation (not having to generate/compile all member functions just because one of them is used will reduce compile time by quite a bit). Slightly more complex is the fact that different member functions in the template might impose different requirements on the instantiating type. For example, operator[] on a map requires that the type of the value is default-constructible, as the operator will create a new element if it did not exist in the map already, on the other hand, if you always use find and insert, you can use std::map with types that are not default constructible. By not forcing the compilation of all member functions, the language allows you to use the template with arguments that would not meet all of the requirements of all of the methods, as long as it does meet the requirements of those methods that are actually used.

I have employed the term used quite a bit in the descriptions above, but I have not yet defined it. For a precise definition you would have to go to the standard, but you can consider as a good approximation that a member function is used if it is called directly or indirectly from your code (i.e. you call it, or some other member function that you instantiate calls it) or if your obtain the address of the member function.


The important point is that a template method in a class is only going to be compiled if some code is calling it. This has the implication that a template method that could NOT be compiled is not a problem if no one is referring to it.

Like a function that is going to generate a runtime error is not a problem unless it's called, a template function that is going to generate a compiler error when instantiated is not a problem unless someone instantiates it. For example:

#include <stdio.h>
#include <string>

template<typename T>
struct Foo
{
    const T& x;

    Foo(const T& x) : x(x) {}

    template<typename S>
    operator S () const
    {
        S s;
        s = x + 1;
        return s;
    }
};

int main()
{
    std::string s = "bar";
    int i = 42;
    Foo<std::string> fs(s);
    Foo<int> fi(i);

    printf("Here we go... -> %f\n", double(fi));
    // printf("This won't compile -> %f\n", double(fs));
    return 0;
}

This code compiles, even if when instantiating Foo<std::string> it would be illegal to instantiate an implicit conversion to double (because x+1 is illegal with std::string).

If you remove the comment instead this is required and the program will not compile.


I believe it is referring to the fact that template code that is not used is never even looked at by the compiler. A result of this is that you can have, for example, syntax errors in a class template that will not cause compilation errors if the class is never used in your code.


The process of replacing template parameters by concrete types is called Instantiation. It results in the Instance of the template. i.e. The compiler generates the code for template function/class with the requested type.

The compiler generates the code for member functions of a template class only if the member function is used(called) or the code is not generated by the compiler at all. This is adherence with the basic principle for C++, You pay for what you use.

The statement from the book explains that.


Yes. "code is instantiated" means the code is put into the memory (code segment). This happens only if the particular method / variable is referred in the code.

(The term Referred doesn't mean the function is called at runtime. It means the method is present somewhere in your code. So if the method is referred then it will be compiled and the code for that will be emitted.)

For example,

template<typename T>
T add(T a, T b) { return a + b; }

Now if you have referring in your code for type double as,

double d = add(2.3, 4.6);

then compiler will emit the code only for add<double>(). There is no point for emitting the code for add<int>() or add<A>().

0

精彩评论

暂无评论...
验证码 换一张
取 消