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

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

Материал из cppreference.com
< cpp‎ | language
 
 
Язык С++
Общие темы
Управление программой
Операторы условного выполнения
Операторы повторения
Операторы перехода
Функции
объявление функции
объявление лямбда-функции
шаблон функции
спецификатор inline
спецификаторы исключений (устарело)
спецификатор noexcept (C++11)
Исключения
Пространства имён
объявление пространства имён
псевдонимы пространства имён
Типы
спецификатор decltype (C++11)
Спецификаторы
cv-спецификаторы
спецификаторы продолжительности хранения
спецификатор constexpr (C++11)
спецификатор auto (C++11)
спецификатор alignas (C++11)
Инициализация
Литералы
Выражения
Утилиты
Типы
typedef-объявление
объявление псевдонима типа (C++11)
атрибуты (C++11)
Приведения типов
неявные преобразования
const_cast-преобразование
static_cast-преобразование
dynamic_cast-преобразование
reinterpret_cast-преобразование
C-подобное и функциональное приведение типов
Выделение памяти
Классы
Особые свойства классовых функций
Специальные функции-члены
Шаблоны
шаблон класса
шаблон функции
специализация шаблона
упакованные параметры (C++11)
Разное
Ассемблерные вставки
 

Псевдоним типа является именем, ссылающимся на ранее определённый тип (наподобие 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

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

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

[править] Пример

#include <string>
#include <ios>
#include <type_traits>
 
// псевдоним типа, полностью эквивалентный
// 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 Container>
void fn2(const Container& c)
{
    typename Container::value_type 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 t) { return 1; } 
 
struct S { virtual ~S() {} };
int main() 
{
    Container<int> c;
    fn2(c); // Container::value_type в этой функции будет равен int
 
//    fpoly_only(c); // ошибка, enable_if такое запрещает
    S s;
    fpoly_only(s); // всё в порядке, enable_if такое позволяет
}


[править] Смотрите также

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