X Tutup
The Wayback Machine - https://web.archive.org/web/20221103184733/https://ru.cppreference.com/w/cpp/language/decltype
Пространства имён
Варианты
Действия

Спецификатор decltype

Материал из cppreference.com
< cpp‎ | language
 
 
Язык С++
Общие темы
Управление потоком
Операторы условного выполнения
if
Операторы итераций (циклы)
Операторы переходов
Функции
Объявление функции
Выражение лямбда-функции
Спецификатор inline
Спецификации динамических исключений (до C++20)
Спецификатор noexcept (C++11)
Исключения
Пространства имён
Типы
Спецификаторы
decltype (C++11)
auto (C++11)
alignas (C++11)
Спецификаторы длительности хранения
Инициализация
Выражения
Альтернативные представления
Литералы
Логические - Целочисленные - С плавающей запятой
Символьные - Строковые - nullptr (C++11)
Определённые пользователем (C++11)
Утилиты
Атрибуты (C++11)
Типы
Объявление typedef
Объявление псевдонима типа (C++11)
Приведения
Неявные преобразования - Явные преобразования
static_cast - dynamic_cast
const_cast - reinterpret_cast
Выделение памяти
Классы
Свойства функции, зависящие от класса
explicit (C++11)
static
Специальные функции-элементы
Шаблоны
Разное
 
Обьявления
Объявления
ссылка
указатель
массив
Block declarations
простое объявление
объявление структурных привязок (C++17)
объявление псевдонимов(C++11)
объявление псевдонимов пространств имён
using-declaration
директива using
объявление static_assert (C++11)
определение asm
объявление непрозрачного enum(C++11)
Другие объявления
определение пространств имён
объявление функции
объявление шаблона класса
объявление шаблона функции
явное инстанцирование шаблона(C++11)
явная специализация шаблона
спецификация связывания
объявление атрибута (C++11)
пустое объявление
 

Проверяет объявленный тип сущности или тип и категорию значения выражения.

Содержание

[править] Синтаксис

decltype ( сущность ) (1) (начиная с C++11)
decltype ( выражение ) (2) (начиная с C++11)

[править] Объяснение

1) Если аргумент представляет собой идентификатор-выражения или выражение доступа к элементу класса без скобок, то decltype возвращает тип сущности, именованной этим выражением. Если такой сущности нет или если аргумент именует набор перегруженных функций, программа некорректа.

Если аргумент представляет собой идентификатор-выражения без скобок, именующий структурное связывание, то decltype возвращает ссылочный тип (описано в спецификации объявления структурного связывания).

(начиная с C++17)

Если аргумент представляет собой идентификатор-выражения без скобок, именующий параметр шаблона не тип, то decltype возвращает тип параметра шаблона (после выполнение любого необходимого вывода типа, если параметр шаблона объявлен с типом-заполнителем). Тип не является константным, даже если сущность является объектом параметра шаблона (который является константным объектом).

(начиная с C++20)
2) Если аргумент является любым другим выражением типа T и
a) если категория значения выражения равна xvalue, тогда decltype даёт T&&;
b) если категория значения выражения равна lvalue, тогда decltype даёт T&;
c) если категория значения выражения равна prvalue, тогда decltype даёт T.

Если выражение является вызовом функции, которая возвращает prvalue типа класса, или является выражением запятой, правым операндом которого является такой вызов функции, временный объект для этого prvalue не вводится.

(до C++17)

Если выражение является значением prvalue отличным от (возможно, в скобках) немедленного вызова (начиная с C++20), временный объект не является материализованным из этого prvalue: такое значение prvalue не имеет объекта результата.

(начиная с C++17)
Поскольку временный объект не создаётся, тип не обязательно должен быть полным или иметь доступный деструктор и может быть абстрактным. Это правило не применяется к подвыражениям: в decltype(f(g())), g() должны иметь полный тип, но f() не нужна.

Обратите внимание, что если имя объекта заключено в круглые скобки, оно обрабатывается как обычное выражение lvalue, поэтому decltype(x) и decltype((x)) часто являются разными типами.

decltype полезно при объявлении типов, которые сложно или невозможно объявить с использованием стандартной нотации, например, типы, связанные с лямбда-выражениями, или типы, зависящие от параметров шаблона.

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

Макрос Тестирования функциональности Значение Стандарт
__cpp_decltype 200707L (C++11)

[править] Ключевые слова

decltype

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

#include <iostream>
#include <type_traits>
 
struct A { double x; };
const A* a;
 
decltype(a->x) y;       // тип y это double (объявленный тип)
decltype((a->x)) z = y; // тип z это const double& (выражение lvalue)
 
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) // возвращаемый тип зависит от параметров шаблона
                                      // тип возвращаемого значения можно вывести,
                                      // начиная с С++14
{
    return t + u;
}
 
const int& getRef(const int* p) { return *p; }
static_assert(std::is_same_v<decltype(getRef), const int&(const int*)>);
auto getRefFwdBad(const int* p) { return getRef(p); }
static_assert(std::is_same_v<decltype(getRefFwdBad), int(const int*)>,
    "Простой возврат auto не является идеальной пересылкой.");
decltype(auto) getRefFwdGood(const int* p) { return getRef(p); }
static_assert(std::is_same_v<decltype(getRefFwdGood), const int&(const int*)>,
    "Возврат decltype(auto) идеально перенаправляет возвращаемый тип.");
 
// Альтернатива:
auto getRefFwdGood1(const int* p) -> decltype(getRef(p)) { return getRef(p); }
static_assert(std::is_same_v<decltype(getRefFwdGood1), const int&(const int*)>,
    "Возврат decltype(выражение return) также отлично перенаправляет возвращаемый тип.");
 
int main()
{
    int i = 33;
    decltype(i) j = i * 2;
 
    std::cout << "i и j одного типа? " << std::boolalpha
              << std::is_same_v<decltype(i), decltype(j)> << '\n';
 
    std::cout << "i = " << i << ", "
              << "j = " << j << '\n';
 
    auto f = [](int a, int b) -> int
    {
        return a * b;
    };
 
    decltype(f) g = f; // тип лямбда-функции уникален и не имеет имени
    i = f(2, 2);
    j = g(3, 3);
 
    std::cout << "i = " << i << ", "
              << "j = " << j << '\n';
}

Вывод:

i и j одного типа? true
i = 33, j = 66
i = 4, j = 9

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

спецификатор auto (C++11) специфицирует тип, полученный из выражения [править]
(C++11)
получает ссылку на свой аргумент для использования в невычисленном контексте
(шаблон функции) [править]
(C++11)
проверяет, являются ли два типа одним и тем же типом
(шаблон класса) [править]
X Tutup