Псевдоним типа, псевдоним шаблона (начиная с 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>::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
|
создаёт синоним для типа |
псевдоним пространства имён | создаёт псевдоним существующего пространства имён |