Ready to practice?
Sign up to access interactive coding exercises and track your progress.
Creating Template Type Aliases
Learn how to write generic, reusable code using alias templates.
Alias templates
In the Type Aliases lesson, we discussed how type aliases let us define an alias for an existing type.
Creating a type alias for a class template where all template arguments are explicitly specified works just like a normal type alias:
#include <iostream>
template <typename T>
struct CoordPair
{
T x {};
T y {};
};
template <typename T>
void print(const CoordPair<T>& c)
{
std::cout << c.x << ' ' << c.y << '\n';
}
int main()
{
using Position = CoordPair<int>; // create normal type alias
Position pixel { 100, 200 }; // compiler replaces this with CoordPair<int>
print(pixel);
return 0;
}
Such aliases can be defined locally (e.g., inside a function) or globally.
Alias templates
In other cases, we might want a type alias for a template class where not all of the template arguments are defined as part of the alias (and will instead be provided by the user of the type alias). To do this, we can define an alias template, which is a template that can be used to instantiate type aliases. Just like type aliases do not define distinct types, alias templates do not define distinct types.
Here's an example of how this works:
#include <iostream>
template <typename T>
struct CoordPair
{
T x {};
T y {};
};
// Here's our alias template
// Alias templates must be defined in global scope
template <typename T>
using Point = CoordPair<T>; // Point is an alias for CoordPair<T>
// Our print function template needs to know that Point's template parameter T is a type template parameter
template <typename T>
void print(const Point<T>& p)
{
std::cout << p.x << ' ' << p.y << '\n';
}
int main()
{
Point<int> pixel1 { 100, 200 }; // Pre C++-20: We must explicitly specify all type template argument
Point pixel2 { 100, 200 }; // In C++20, we can use alias template deduction to deduce the template arguments in cases where CTAD works
std::cout << pixel1.x << ' ' << pixel1.y << '\n';
print(pixel2);
return 0;
}
In this example, we're defining an alias template named Point as an alias for CoordPair<T>, where type template parameter T will be defined by the user of the Point alias. Point is the alias template, and Point<T> is the instantiated type alias for CoordPair<T>. Once defined, we can use Point where we would use CoordPair, and Point<T> where we would use CoordPair<T>.
There are a couple of things worth noting about this example.
First, unlike normal type aliases (which can be defined inside a block), alias templates must be defined in the global scope (as all templates must).
Second, prior to C++20, we must explicitly specify the template arguments when we instantiate an object using an alias template. As of C++20, we can use alias template deduction, which will deduce the type of the template arguments from an initializer in cases where the aliased type would work with CTAD.
Third, because CTAD doesn't work on function parameters, when we use an alias template as a function parameter, we must explicitly define the template arguments used by the alias template. In other words, we do this:
template <typename T>
void print(const Point<T>& p)
{
std::cout << p.x << ' ' << p.y << '\n';
}
Not this:
void print(const Point& p) // won't work, missing template arguments
{
std::cout << p.x << ' ' << p.y << '\n';
}
This is no different than if we'd used CoordPair or CoordPair<T> instead of Point or Point<T>.
Summary
Normal type aliases with class templates: Create type aliases for fully-specified class templates using standard using syntax: using Position = CoordPair<int>;. These aliases work like any other type alias and can be defined locally or globally.
Alias templates: Define template aliases where some template arguments remain unspecified using template <typename T> using Point = CoordPair<T>;. This creates an alias template that users can instantiate with their chosen type arguments.
Alias template syntax: Alias templates must be defined in global scope (like all templates). The alias name (Point) acts as a template that produces type aliases when instantiated (Point<int> is an alias for CoordPair<int>).
Alias template deduction (C++20): Starting in C++20, alias templates support deduction from initializers when the aliased type supports CTAD: Point pixel { 100, 200 }; deduces Point<int>. Prior to C++20, template arguments must be specified explicitly.
Function parameters with alias templates: CTAD doesn't work with function parameters, so template arguments must be explicit. Use template <typename T> void print(const Point<T>& p) instead of void print(const Point& p).
Alias templates don't create new types: Like regular type aliases, alias templates don't define distinct types - they're just alternative names for existing types. Point<int> and CoordPair<int> are the exact same type.
Benefits of alias templates: Provide more convenient or descriptive names for complex template types, allow partial specification of template arguments, and can make generic code more readable while maintaining full type information.
Alias templates are particularly useful for simplifying long or complex template type names, creating semantic aliases that make code intent clearer, and providing backward-compatible interfaces when refactoring template code.
Creating Template Type Aliases - Quiz
Test your understanding of the lesson.
Practice Exercises
Type Aliases for Coordinates
Create alias templates to simplify working with coordinate pairs. Demonstrate both normal type aliases and alias templates.
Lesson Discussion
Share your thoughts and questions
No comments yet. Be the first to share your thoughts!