Type Aliases and Alias Templates in C++

This article provides a practical overview of type aliases and alias templates introduced in C++11 using the using syntax. You will learn the fundamental syntax of modern type aliases, how they compare to traditional typedef declarations, and how alias templates solve long-standing metaprogramming limitations by allowing parameterized type synonyms.

What is a Type Alias?

A type alias is an alternative name for an existing data type. In modern C++, type aliases are declared using the using keyword followed by the identifier name and the target type.

using Integer = int;
using StringList = std::vector<std::string>;

Once defined, Integer and StringList can be used interchangeably with their underlying types. They do not introduce new distinct types; they are purely synonyms evaluated at compile time.

Advantages Over typedef

Prior to C++11, creating type synonyms required the typedef keyword:

typedef int Integer;
typedef void (*FunctionPointer)(int, double);

While functional, typedef syntax becomes difficult to read when dealing with complex types, such as function pointers or arrays. The using syntax aligns with standard variable assignment syntax (name = value):

using FunctionPointer = void (*)(int, double);

The identifier always appears on the left side of the assignment operator, making definitions significantly easier to parse visually.

What are Alias Templates?

The most critical advantage of the using syntax is its native support for templates. An alias template allows you to define a family of type aliases parameterized by one or more template arguments.

Prior to C++11, creating a templated alias using typedef required wrapping it in a templated struct:

// C++98 workaround
template <typename T>
struct StringMap {
    typedef std::map<std::string, T> type;
};

// Usage
StringMap<int>::type myMap;

With modern C++, alias templates achieve this directly and cleanly:

// Modern C++
template <typename T>
using StringMap = std::map<std::string, T>;

// Usage
StringMap<int> myMap;

Advanced Template Specialization

Alias templates can also bind specific arguments while leaving others generic. For example, fixing an allocator or a key type for standard library containers:

template <typename Value>
using IntKeyMap = std::map<int, Value, std::greater<int>>;

IntKeyMap<std::string> scores; // std::map<int, std::string, std::greater<int>>

Standard Library Adoption

The C++ standard library heavily utilizes alias templates. Starting in C++14, standard type traits provide alias templates ending in _t to replace the verbose typename std::trait<T>::type idiom:

// C++11 style
typename std::decay<T>::type value1;

// Modern style using standard alias template
std::decay_t<T> value2;

Under the hood, the standard library implements these using the exact same mechanism:

namespace std {
    template <typename T>
    using decay_t = typename decay<T>::type;
}

Summary

  • Type Aliases (using NewName = Type;): Provide clean, readable synonyms for existing types, directly replacing typedef.
  • Alias Templates (template <...> using NewName = Type<...>;): Allow type synonyms to accept template parameters, eliminating the need for nested struct workarounds.