Спецификатор decltype
Проверяет объявленный тип сущности или тип и категорию значения выражения.
Синтаксис
decltype ( сущность )
|
(1) | (начиная с C++11) | |||||||
decltype ( выражение )
|
(2) | (начиная с C++11) | |||||||
Объяснение
|
Если аргумент представляет собой идентификатор-выражения без скобок, именующий структурное связывание, то decltype возвращает ссылочный тип (описано в спецификации объявления структурного связывания). |
(начиная с C++17) |
|
Если аргумент представляет собой идентификатор-выражения без скобок, именующий параметр шаблона не тип, то decltype возвращает тип параметра шаблона (после выполнение любого необходимого вывода типа, если параметр шаблона объявлен с типом-заполнителем). Тип не является константным, даже если сущность является объектом параметра шаблона (который является константным объектом). |
(начиная с C++20) |
T и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) |
Ключевые слова
Пример
#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;
static_assert(std::is_same_v<decltype(i), decltype(j)>);
assert(i == 33 && 66 == j);
auto f = [i](int a, int b) -> int { return a * b + i; };
auto h = [i](int a, int b) -> int { return a * b + 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
Смотрите также
спецификатор auto (C++11)
|
специфицирует тип, полученный из выражения |
(C++11) |
получает ссылку на свой аргумент для использования в невычисленном контексте (шаблон функции) |
(C++11) |
проверяет, являются ли два типа одним и тем же типом (шаблон класса) |
Документация C по typeof
| |