Namespaces
Variants

decltype specifier (since C++11)

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
const / volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

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

Содержание

Синтаксис

decltype ( entity ) (1)
decltype ( expression ) (2)

Объяснение

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

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

(since C++17)

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

(since C++20)
2) Если аргумент является любым другим выражением типа T , и
a) если категория значения выражения является xvalue , тогда decltype возвращает T && ;
б) если категория значения expression является 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

Ключевые слова

decltype

Пример

#include <cassert>
#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) // возвращаемый тип зависит от параметров шаблона
                                      // возвращаемый тип может быть выведен начиная с C++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(выражение возврата) также идеально пересылает возвращаемый тип.");
int main()
{
    int i = 33;
    decltype(i) j = i * 2;
    static_assert(std::is_same_v<decltype(i), decltype(j)>);
    assert(i == 33 && 66 == j);
    auto f = [i](int av, int bv) -> int { return av * bv + i; };
    auto h = [i](int av, int bv) -> int { return av * bv + i; };
    static_assert(!std::is_same_v<decltype(f), decltype(h)>,
        "Тип лямбда-функции уникален и не имеет имени");
    decltype(f) g = f;
    std::cout << f(3, 3) << ' ' << g(3, 3) << '\n';
}

Вывод:

42 42

Ссылки

Расширенное содержимое
  • Стандарт C++23 (ISO/IEC 14882:2024):
  • 9.2.9.5 Спецификаторы decltype [dcl.type.decltype]
  • Стандарт C++20 (ISO/IEC 14882:2020):
  • 9.2.8.4 Спецификаторы decltype [dcl.type.decltype]
  • Стандарт C++17 (ISO/IEC 14882:2017):
  • TBD Спецификаторы decltype [dcl.type.decltype]
  • Стандарт C++14 (ISO/IEC 14882:2014):
  • TBD Спецификаторы decltype [dcl.type.decltype]
  • Стандарт C++11 (ISO/IEC 14882:2011):
  • TBD Спецификаторы decltype [dcl.type.decltype]

Смотрите также

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