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

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

Материал из cppreference.com
< cpp‎ | language
 
 
Язык С++
Общие темы
Управление потоком
Операторы условного выполнения
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 создаёт синоним для типа[править]
псевдоним пространства имён создаёт псевдоним существующего пространства имён[править]