Пространства имён
Варианты
Действия

Псевдоним типа, псевдоним шаблона (начиная с C++11)

Материал из cppreference.com
 
 
Язык С++
Общие темы
Управление потоком
Операторы условного выполнения
if
Операторы итерации (циклы)
Операторы перехода
Функции
Объявление функции
Выражение лямбда-функции
Спецификатор inline
Спецификации динамических исключений (до C++17*)
Спецификатор noexcept (C++11)
Исключения
Пространства имён
Типы
Спецификаторы
decltype (C++11)
auto (C++11)
alignas (C++11)
Спецификаторы длительности хранения
Инициализация
Выражения
Альтернативные представления
Литералы
Логические - Целочисленные - С плавающей запятой
Символьные - Строковые - nullptr (C++11)
Определяемые пользователем (C++11)
Утилиты
Атрибуты (C++11)
Types
Объявление typedef
Объявление псевдонима типа (C++11)
Casts
Неявные преобразования - Явные преобразования
static_cast - dynamic_cast
const_cast - reinterpret_cast
Выделение памяти
Классы
Свойства функции класса
explicit (C++11)
static
Специальные функции-элементы
Шаблоны
Разное
 

Псевдоним типа является именем, ссылающимся на ранее определённый тип (наподобие typedef)

Псевдоним шаблона является именем, ссылающимся на семейство типов.

Синтаксис

Объявления псевдонимов являются объявлениями блока со следующим синтаксисом

using идентификатор атрибуты (необязательно) = идентификатор-типа ; (1)
template < список-параметров-шаблона >

using идентификатор атрибуты (необязательно) = идентификатор-типа ;

(2)
атрибуты(C++11) необязательная последовательность любого количества атрибутов
идентификатор имя, вводимое этим объявлением, которое может быть как именем типа (1) так и именем шаблона (2)
список-параметров-шаблона список параметров шаблона, как и в объявлении шаблона
идентификатор-типа абстрактный описатель, либо любой другой допустимый идентификатор-типа (который может вводить новый тип, как указано в описании идентификатора-типа). идентификатор-типа не может ссылаться на идентификатор, ни прямо, ни косвенно. Обратите внимание, что точка объявления идентификатора находится на месте точки с запятой, следующей за идентификатором-типа.

Разъяснение

1) Объявление псевдонима типа вводит имя, которое может использоваться в качестве синонима типа, обзначенного идентификатором-типа. Оно не вводит новый тип и не может изменить значение существующего имени типа. Между псевдонимом типа и объявлением typedef нет никакой разницы. Это объявление может появиться в области видимости блока, области видимости класса или области видимости пространства имён.
2) Псевдоним шаблона является шаблоном, который, при специализации, эквивалентен результату подстановки шаблонных аргументов псевдонима шаблона на место параметров шаблона в идентификаторе-типа
template<class T> struct Alloc {};
template<class T> using Vec = vector<T, Alloc<T>>; // идентификатор-типа является vector<T, Alloc<T>>
Vec<int> v; // Vec<int> означает тоже самое, что и vector<int, Alloc<int>>

Если результат специализации псевдонима шаблона зависит от идентификатора-шаблона, последующие подстановки применяются к этому идентификатору-шаблона:

template<typename...> using void_t = void;
template<typename T> void_t<typename T::foo> f();
f<int>(); // ошибка, int не имеет вложенного типа foo
(начиная с C++17)

Тип производится в том случае, если специализации псевдонима шаблона прямо или косвенно не разрешается использовать свой собственный тип:

template <class T> struct A;
template <class T> using B = typename A<T>::U; // идентификатор-типа здесь равен A<T>::U
template <class T> struct A {
    typedef B<T> U;
};
B<short> b; // ошибка: B<short> использует свой собственный тип через A<short>::U

Псевдонимы шаблонов никогда не выводятся механизмом вывода шаблонных аргументов при выводе шаблонных шаблонных параметров.

Псевдоним шаблона невозможно специализировать частично или явно.

Как и любое объявление шаблона, псевдоним шаблон может быть объявлен только в области видимости класса или области видимости пространства имён.

Тип лямбда-выражения появляющийся в объявлении псевдонима шаблона, различается в разных экземплярах этого шаблона, даже если лямбда-выражение не зависит.

template <class T>
using A = decltype([] { }); // A<int> и A<char> относятся к разным типам замыкания
(начиная с C++20)

Примечание

Макрос Тестирования функциональности Значение Стандарт Функциональность
__cpp_alias_templates 200704L (C++11) Шаблоны псевдонимов

Пример

#include <iostream>
#include <string>
#include <type_traits>
#include <typeinfo>

// псевдоним типа, полностью эквивалентный
// typedef std::ios_base::fmtflags flags;
using flags = std::ios_base::fmtflags;
// имя 'flags' теперь обозначает тип:
flags fl = std::ios_base::dec;

// псевдоним типа, полностью эквивалентный
// typedef void (*func)(int, int);
using func = void (*) (int,int);
// имя 'func' теперь обозначает указатель на функцию:
void example(int, int) {}
func fn = example;

// псевдоним шаблона
template<class T> using ptr = T*; 
// имя 'ptr<T>' теперь является псевдонимом для указателя на T
ptr<int> x;

// псевдоним типа используется для сокрытия шаблонного параметра
template <class CharT> using mystring = 
    std::basic_string<CharT,std::char_traits<CharT>>;
mystring<char> str;

// псевдоним типа может ввести элемент имени типа
template<typename T>
struct Container {
    using value_type = T;
};
// который может использоваться в обобщённом программировании
template<typename ContainerT>
void info(const ContainerT& c)
{
    typename ContainerT::value_type T;
    std::cout << "ContainerT равно `" << typeid(decltype(c)).name() << "`\n"
                 "value_type равно `" << typeid(T).name() << "`\n";
}

// псевдоним типа используется для упрощения синтаксиса std::enable_if
template<typename T>
using Invoke = typename T::type;
template<typename Condition>
using EnableIf = Invoke<std::enable_if<Condition::value>>;
template<typename T, typename = EnableIf<std::is_polymorphic<T>>>
int fpoly_only(T) { return 1; }

struct S { virtual ~S() {} };
int main() 
{
    Container<int> c;
    info(c); // Container::value_type в этой функции будет равен int
//    fpoly_only(c); // ошибка, enable_if такое запрещает
    S s;
    fpoly_only(s); // всё в порядке, enable_if такое позволяет
}

Возможный вывод:

ContainerT равно `struct Container<int>`
value_type равно `int`

Отчёты о дефектах

Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:

Номер Применён Поведение в стандарте Корректное поведение
CWG 1558 C++11 не указано, участвуют ли в подстановке неиспользуемые
аргументы в специализации псевдонима
подстановка выполняется

Смотрите также

объявление typedef создаёт синоним для типа[править]
псевдоним пространства имён создаёт псевдоним существующего пространства имён[править]