Spec-Zone.ru › C++

decltype спецификатор (начиная с C++11)

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

Синтаксис

decltype ( сущность ) (1)
decltype ( выражение ) (2)

Пояснение

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

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

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

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

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

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

(начиная с C++26)
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

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

decltype

Пример

#include <cassert>
#include <iostream>
#include <type_traits>

struct A { double x; };
const A* a;

decltype(a->x) y;       // type of y is double (declared type)
decltype((a->x)) z = y; // type of z is const double& (lvalue expression)

template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) // return type depends on template parameters
                                      // return type can be deduced since 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*)>,
    "Just returning auto isn't perfect forwarding.");
decltype(auto) getRefFwdGood(const int* p) { return getRef(p); }
static_assert(std::is_same_v<decltype(getRefFwdGood), const int&(const int*)>,
    "Returning decltype(auto) perfectly forwards the return type.");

// Alternatively:
auto getRefFwdGood1(const int* p) -> decltype(getRef(p)) { return getRef(p); }
static_assert(std::is_same_v<decltype(getRefFwdGood1), const int&(const int*)>,
    "Returning decltype(return expression) also perfectly forwards the return type.");

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)>,
        "The type of a lambda function is unique and unnamed");

    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) задаёт тип, выведенный из выражения
declval
(C++11)
получает ссылку на объект типа аргумента шаблона для использования в невычисляемом контексте
(шаблон функции)
is_same
(C++11)
проверяет, являются ли два типа одинаковыми
(шаблон класса)
underlying_type
(C++11)
получает базовый целочисленный тип для заданного типа перечисления
(шаблон класса)
Документация по C для typeof

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/decltype

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API