Псевдоним типа, псевдоним шаблона (начиная с C++11)
Псевдоним типа является именем, ссылающимся на ранее определённый тип (наподобие typedef
)
Псевдоним шаблона является именем, ссылающимся на семейство типов.
Содержание |
[править]Синтаксис
Объявления псевдонимов являются объявлениями блока со следующим синтаксисом
using идентификаторатрибуты (необязательно)= идентификатор-типа; | (1) | ||||||||
template < список-параметров-шаблона>
| (2) | ||||||||
атрибуты(C++11) | — | необязательная последовательность любого количества атрибутов |
идентификатор | — | имя, вводимое этим объявлением, которое может быть как именем типа (1) так и именем шаблона (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>::Utemplate<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_iftemplate<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){return1;} 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 | создаёт синоним для типа |
псевдоним пространства имён | создаёт псевдоним существующего пространства имён |