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.
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.
Modernes C++ Mentoring
Do you want to stay informed: Subscribe.
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.
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.
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::list. std::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.
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, 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, 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, Philipp Lenk, Charles-Jianye Chen, Keith Jeffery,and Matt Godbolt.
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 |
Modernes C++ GmbH
Modernes C++ Mentoring (English)
Rainer Grimm
Yalovastraße 20
72108 Rottenburg
Mail: schulung@ModernesCpp.de
Mentoring: www.ModernesCpp.org
Modernes C++ Mentoring,
Leave a Reply
Want to join the discussion?Feel free to contribute!