templatesParameters

Alias Templates and Template Parameters

Today, I write about two topics: alias templates and template parameters. Alias templates are a way to give a name to a family of types. Template parameters can be types, non-types, and templates themselves.

 templatesParameters

Let’s start with the alias templates.

Alias Templates

With C++11, we got alias templates. Alias templates provide a means to give a convenient name to a family of types. The following code snippet presents the idea for the class template Matrix.

template <typename T, int Line, int Col>
class Matrix{
    ....
};

 

Matrix has three template parameters. The type parameter, and the non-type parameters, and Col (I will write about template parameters in the next section.)

For readability, I want to have two special matrices: a Square and a Vector. A Square‘s number of lines and columns should be equal. A Vector‘s line size should be one. Thanks to type aliases, I can express my ideas directly in code.

template <typename T, int Line>
using Square = Matrix<T, Line, Line>; // (1)

template <typename T, int Line>
using Vector = Matrix<T, Line, 1>;    // (2)

 

The keyword using ((1) and (2)) declares a type alias. While the primary template Matrix can be parametrized in the three dimensions T, Line, and Col, the type aliases Square and Vector reduce the parametrization to the two dimensions T and Line. From this point of view, alias templates enable it to create intuitive names for partially bound templates. Using Square and Vector is straightforward.

Matrix<int, 5, 3> ma;
Square<double, 4> sq;
Vector<char, 5> vec;

 

An excellent use case of alias templates is the type-traits library.

 

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.

     

    Type-Traits Library

    When you apply std::move(arg) on a value arg, the compiler uses typically std::remove_reference to remove a reference from the underlying type:

    static_cast<std::remove_reference<decltype(arg)>::type&&>(arg);   // (1)
    
    static_cast<std::remove_reference_t<decltype(arg)>&&>(arg);       // (2)
    

     

    Thanks to alias templates, version (line 2) have been valid since C++14. The following helper type is available:

    template< class T >
    using remove_reference_t = typename remove_reference<T>::type;
    

     

    Of course, the corresponding helper types for the other functions of the type-traits library returning a type are also available with C++14.

     

    The previously defined class template Matrix uses the two non-type template parameters Line and Col.

    Template Parameters

     Template parameters can be types, non-types, and templates themselves.

    Types

    Okay, types are the most often used template parameters. Here are a few examples:

    std::vector<int> myVec;
    std::map<std::string, int> myMap;
    std::lock_guard<std::mutex> myLockGuard;
    

    Non-Types

    Non-types can be a

    • lvalue reference
    • nullptr
    • pointer
    • enumerator of a enum
    • integral values
    • floating-point values (C++20)

    Integral values are the most used non-types. std::array is the typical example because you have to specify at compile time the size of a std::array:

    std::array<int, 3> myArray{1, 2, 3};
    

    Templates

    Templates themself can be template parameters. Their definition may look a bit weird.

    // templateTemplateParameters.cpp
    
    #include <iostream>
    #include <list>
    #include <vector>
    #include <string>
    
    template <typename T, template <typename, typename> class Cont >    // (1)
    class Matrix{
    public:
      explicit Matrix(std::initializer_list<T> inList): data(inList) {  // (2)
        for (auto d: data) std::cout << d << " ";
      }
      int getSize() const{
        return data.size();
      }
    
    private:
      Cont<T, std::allocator<T>> data;                                  // (3)                               
    
    };
    
    int main(){
    
      std::cout << '\n';
    
                                                                        // (4)
      Matrix<int, std::vector> myIntVec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
      std::cout << '\n';
      std::cout << "myIntVec.getSize(): " << myIntVec.getSize() << '\n';
    
      std::cout << std::endl;
    
      Matrix<double, std::vector> myDoubleVec{1.1, 2.2, 3.3, 4.4, 5.5}; // (5)
      std::cout << '\n';
      std::cout << "myDoubleVec.getSize(): "  << myDoubleVec.getSize() << '\n';
    
      std::cout << '\n';
                                                                        // (6)
      Matrix<std::string, std::list> myStringList{"one", "two", "three", "four"};  
      std::cout << '\n';
      std::cout << "myStringList.getSize(): " << myStringList.getSize() << '\n';
    
      std::cout << '\n';
    
    }
    

     

    Matrix is a simple class template that can be initialized by a std::initializer_list (line 2). A Matrix can be used with a std::vector (line 4 and line 5) or a std::list (line 6) to hold its values. So far, nothing special. 

    templateTemplateParameters

    But hold, I forget to mention lines 1 and 3. Line 1 declares a class template that has two template parameters. Okay, the first parameter is the type of the elements, and the second parameter stands for the container. Look at the second parameter: template <typename, typename> class Cont >. This means the second template argument should be a template requiring two template parameters. The first template parameter is the type of elements the container stores, and the second is the defaulted allocator a container of the standard template library has. Even the allocator has a default value, such as in the case of a std::vector. The allocator depends on the type of elements.

    template<
        class T,
        class Allocator = std::allocator<T>
    > class vector;
    

     

    Line 3 shows the usage of the allocator in this internally used container. The matrix can use all containers, which are of the kind: container< type of the elements, allocator of the elements>. This is true for the sequence containers such as std::vector, std::deque, or std::liststd::array and std::forward_list would fail because std::array needs an additional non-type for specifying its size at compile-time and std::forward_list does not support the size method.

    Maybe you don’t like the keyword class for the name of the template template parameter. With C++17, you can replace class with typename:

     

    template <typename T, template <typename, typename> class Cont >    // (1)
    class Matrix;
    
    template <typename T, template <typename, typename> typename Cont > // (2) 
    class Matrix;
    

     

    Line (2) is valid since C++17 and is equivalent to line (1).

    The Next pdf Bundle: Coroutines

    In the post “Which pdf bundle do you want? Make your choice!” you decided on the coroutines bundle.

    pollResult

    I’m still preparing the bundle, but it should be available in the next few days.

    If you subscribe to the English newsletter, you automatically get the link to the current pdf bundle. Have a look at the top right corner of this page. This automatism makes it quite comfortable for me. People that are already subscribed to my newsletter get the link automatically.

    What’s next?

    In my next post, I will write about template arguments. It is pretty interesting how the compiler deduces the types. The rules do not only apply to function templates (C++98) but also to auto (C++11), to class templates (C++17), and concepts (C++20).

     

    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, 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, Philipp Lenk, Hobsbawm, and Charles-Jianye Chen.

    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 *