templatesInstantiation

Template Instantiation

Template instantiation is creating a concrete function or a concrete class out of a function or class template. Creating template instantiation can be implicit (compiler-generated) or explicit (user-provided).

 templatesInstantiation

When you need a template for a specific argument, the compiler auto-generates it. Sometimes, you want to remove template definitions from header files or avoid compute-power-consuming template instantiation. In this case, explicit instantiation is your friend.

Implicit Instantiation

Implicit instantiation should be your default choice. Implicit instantiation means the compiler automatically generates the concrete function or class for the provided template arguments. The compiler also deduces the template arguments from the function’s arguments. In C++17, the compiler can also deduce the template arguments for class templates.

 

 

Rainer D 6 P2 500x500Modernes C++ Mentoring

Be part of my mentoring programs:

  • "Fundamentals for C++ Professionals" (open)
  • "Design Patterns and Architectural Patterns with C++" (open)
  • "C++20: Get the Details" (open)
  • "Concurrency with Modern C++" (starts March 2024)
  • Do you want to stay informed: Subscribe.

     

    // implicitTemplateInstantiation.cpp
    
    #include <iostream>
    #include <string>
    #include <vector>
    
    template <typename T>
    class MyClass{
     public:
        MyClass(T t) { }
        std::string getType() const {
            return typeid(T).name();
        }
    };
    
    template<typename T>
    bool isSmaller(T fir, T sec){
        return fir < sec;
    }
    
    int main(){
    
        std::cout << '\n';
    
        std::cout << std::boolalpha;
      
        std::vector vec{1, 2, 3, 4, 5};          // (1)
        std::cout << "vec.size(): " << vec.size() << '\n';
      
        MyClass myClass(5);                      // (2)
        std::cout << "myClass.getType(): " << myClass.getType() << '\n';
      
        std::cout << '\n';
      
        std::cout << "isSmaller(5, 10): " 
                  << isSmaller(5, 10) << '\n';   // (3)
        std::cout << "isSmaller<double>(5.5f, 6.5): " 
                  << isSmaller<double>(5.5f, 6.5) << '\n';    // (4)
      
        std::cout << '\n';
      
    }
    

     

    Lines (1) and (2) use class template argument deduction (CTAG). std::vector or MyClass can deduce its type from their constructor arguments. Line (3) also deduces its template argument. In line (4), on the contrary, the template argument double is explicitly specified: isSmaller<double>(5.5f, 6.5).

    implicitTemplateInstantiation

    The compiler creates for each implicit template instantiation a concrete function or class. C++Insights visualizes this process.

    This automatic process is very comfortable but has a few drawbacks.

    1. When you implicitly instantiate a template, the definition of the template is typically visible in a header file. Maybe, you don’t want to disclose the definition.
    2. When you need a template for specific template arguments, the compiler instantiates if unavailable in the concrete translation unit. A translation unit is the source file after processing the C preprocessor. Typically, the linker removes all redundant template instantiations and keeps one. This is a waste of time and space.

    Both issues can be solved with explicit template instantiation.

    Explicit Instantiation

    Explicit instantiation has two flavors: explicit instantiation definition and explicit instantiation declaration.

    • Explicit instantiation definition syntax: template <template declaration>
    • Explicit instantiation declaration syntax: extern template <template declaration>

    When you study the syntax, the keyword extern makes the difference.

    Explicit template instantiation means that you generate the definition of a template. Here is a simple example.

    // explicitTemplateInstantiation.cpp
    
    #include <iostream>
    #include <string>
    #include <vector>
    
    template <typename T>
    class MyClass{
     public:
        MyClass(T t) { }
        std::string getType() const {
            return typeid(T).name();
        }
    };
    
    template<typename T>
    bool isSmaller(T fir, T sec){
      return fir < sec;
    }
     
    template class std::vector<int>;                       // (1)
    template bool std::vector<double>::empty() const;      // (2)
    
    template class MyClass<int>;                           // (3)
    template std::string MyClass<double>::getType() const; // (4)
    
    template bool isSmaller(int, int);                     // (5)
    template bool isSmaller<double>(double, double);       // (6)
    
    int main(){
    
      std::cout << '\n';
      
      std::cout << std::boolalpha;
      
      std::vector vec{1, 2, 3, 4, 5};
      std::cout << "vec.size(): " << vec.size() << '\n';
      
      MyClass myClass(5);
      std::cout << "myClass.getType(): " << myClass.getType() << '\n';
      
      std::cout << '\n';
      
      std::cout << "isSmaller(5, 10): " 
                << isSmaller(5,10) << '\n';
      std::cout << "isSmaller<double>(5.5f, 6.5): " 
                << isSmaller<double>(5.5f, 6.5) << '\n';
      
      std::cout << '\n';
      
    }
    

     

    Lines (1) to (6) are the interesting ones. Thanks to the keyword template, explicit template instantiation happens.

    • Line (1) explicitly instantiated std::vector for int and line (2) its member function empty for double.
    • Line (3) explicitly instantiates MyClass for int and line (4) its member function getType for double.
    • Line (5) explicitly instantiated isSmaller for (int, int), and line (6) does the same for (double, double) providing the explicit template argument double.

    Hide the Template Implementation

    How can explicit template instantiation help you hide the definition of the templates?

    • Put the template declaration in the header file.
    • Put the template definition in the source file. Explicitly instantiate the template at the end of the source file.
    • Use the template by including the header file.

    Here are three files exemplifying this process.

    • Template declaration

    // MyClass.h
    
    #include <typeinfo>
    #include <string>
    
    template <typename T>
    class MyClass{
     public:
        MyClass(T t) { }
        std::string getType() const;
    };
    

     

    • Template definition and explicit instantiation for int

    // MyClass.cpp
    
    #include "MyClass.h"
    
    template <typename T>
    std::string MyClass<T>::getType() const {
        return typeid(T).name();
    }
    
    template class MyClass<int>; 
    

     

    • Template use

    // mainMyClass.cpp
    
    #include "MyClass.h"
    #include <iostream>
    
    int main() {
    
        std::cout << '\n'; 
    
        MyClass myClass(5);
        std::cout << "myClass.getType(): " << myClass.getType() << '\n';
    
        /*
        MyClass myClass2(5.5);
        std::cout << "myClass2.getType(): " << myClass2.getType() << '\n';
        */
    
        std::cout << '\n';
    
    }
    

     

    Compiling and running the program gives the expected result.

    mainMyClass

    But when I try to use MyClass another type than int, I get a linker error. I get this linker error message when I use the commented-out lines.

    mainMyClassError There is no template instantiation  double available.

    Suppress the Template Instantiation

    Assume you use MyClass<int> in various translation units which the linker puts together. Essentially, the linker throws away all template instantiations but one. This is a waste of computing time. Thanks to the use of the extern keyword in C++11, you can make out of an explicit template instantiation definition an explicit template instantiation declaration. What?

    template class MyClass<int>;        // explicit instantiation definition
    extern template class MyClass<int>; // explicit instantiation declaration 
    

     

    The key observation is that the second line does not cause a template instantiation. This means that the compiler generates not something the linker throws away. You have only to ensure that one instantiation of MyClass<int> is for the linker available. If not, you will get a linker error. 

    What’s next?

    After this more technical post, I will write in my next post about variadic templates … .

     

     

    Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Matthieu Bolt, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Rob North, Bhavith C Achar, Marco Parri Empoli, moon, and Philipp Lenk.

    Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, Slavko Radman, and David Poole.

    My special thanks to Embarcadero
    My special thanks to PVS-Studio
    My special thanks to Tipi.build 
    My special thanks to Take Up Code
    My special thanks to SHAVEDYAKS

    Seminars

    I’m happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.

    Standard Seminars (English/German)

    Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.

    • C++ – The Core Language
    • C++ – The Standard Library
    • C++ – Compact
    • C++11 and C++14
    • Concurrency with Modern C++
    • Design Pattern and Architectural Pattern with C++
    • Embedded Programming with Modern C++
    • Generic Programming (Templates) with C++
    • Clean Code with Modern C++
    • C++20

    Online Seminars (German)

    Contact Me

    Modernes C++ Mentoring,

     

     

    0 replies

    Leave a Reply

    Want to join the discussion?
    Feel free to contribute!

    Leave a Reply

    Your email address will not be published. Required fields are marked *