Spec-Zone.ru › C++

Оператор decltype

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

Синтаксис

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

Описание

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

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

(с C++17)

Если аргумент — это выражение id-выражение без скобок, называющее параметр шаблона нетипового типа, то 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

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

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

См. также

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

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

Spec-Zone.ru

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