decltype
(C++)
Описатель decltype
типов выдает тип указанного выражения. Описатель decltype
типов вместе с auto
ключевым словом полезен в первую очередь разработчикам, которые записывают библиотеки шаблонов. Используйте и decltype
объявите auto
шаблон функции, возвращаемый тип которого зависит от типов его аргументов шаблона. Кроме того, используйте auto
и decltype
объявите шаблон функции, который упаковывает вызов другой функции, а затем возвращает возвращаемый тип упаковаемой функции.
Синтаксис
decltype(
expression
)
Параметры
expression
Выражение . Дополнительные сведения см. в разделе Выражения.
Возвращаемое значение
Тип параметра expression
.
Замечания
Описатель decltype
типов поддерживается в Visual Studio 2010 или более поздних версиях и может использоваться с машинным или управляемым кодом. decltype(auto)
(C++ 14) поддерживается в Visual Studio 2015 и более поздних версиях.
Компилятор использует следующие правила для определения типа expression
параметра.
expression
Если параметр является идентификатором или доступом к члену класса,decltype(expression)
тип сущности сexpression
именем. Если такой сущности илиexpression
параметра нет набора перегруженных функций, компилятор выдает сообщение об ошибке.expression
Если параметр является вызовом функции или перегруженной функции оператора,decltype(expression)
возвращает тип функции. Скобки вокруг перегруженного оператора игнорируются.expression
Если параметр является rvalue,decltype(expression)
является типомexpression
.expression
Если параметр является lvalue,decltype(expression)
это ссылка на lvalue типаexpression
.
В следующем примере кода показано использование decltype
описателя типов. Сначала предположим, что вы закодировали следующие инструкции.
int var;
const int&& fx();
struct A { double x; };
const A* a = new A();
Затем изучите типы, возвращаемые четырьмя decltype
операторами в следующей таблице.
Оператор | Тип | Примечания. |
---|---|---|
decltype(fx()); |
const int&& |
Ссылка rvalue на объект const int . |
decltype(var); |
int |
Тип переменной var . |
decltype(a->x); |
double |
Тип членского доступа. |
decltype((a->x)); |
const double& |
Внутренние скобки вызывают оценку оператора в качестве выражения, а не членского доступа. И потому, что a он объявлен в качестве const указателя, тип является ссылкой на const double . |
decltype
и auto
.
В C++14 можно использовать decltype(auto)
без конечного типа возврата для объявления шаблона функции, возвращаемый тип которого зависит от типов его аргументов шаблона.
В C++11 можно использовать decltype
описатель типов для конечного возвращаемого типа вместе с auto
ключевым словом, чтобы объявить шаблон функции, возвращаемый тип которого зависит от типов его аргументов шаблона. Например, рассмотрим следующий пример кода, в котором возвращаемый тип шаблона функции зависит от типов аргументов шаблона. В примере кода заполнитель указывает, UNKNOWN
что возвращаемый тип нельзя указать.
template<typename T, typename U>
UNKNOWN func(T&& t, U&& u){ return t + u; };
Введение decltype
описателя типов позволяет разработчику получить тип выражения, возвращаемого шаблоном функции. Используйте синтаксис объявления альтернативной функции, показанный позже, auto
ключевое слово и decltype
описатель типа, чтобы объявить тип возвращаемого значения с поздним значением. Тип возвращаемого значения, заданного в конце, определяется при компиляции объявления, а не при коде.
Следующий прототип иллюстрирует синтаксис альтернативного объявления функции. Квалификаторы const
и volatile
throw
спецификация исключения являются необязательными. Заполнитель function_body
представляет составную инструкцию, которая указывает, что выполняет функция. В качестве оптимальной методики expression
написания кода заполнитель в decltype
инструкции должен соответствовать выражению, указанному return
оператором, если таковой function_body
имеется.
auto
function_name
(
parameters
const
)
opt opt volatile
->
decltype(
expression
)
noexcept
{
function_body
};
В следующем примере кода тип возвращаемого myFunc
типа шаблона функции определяется типами t
аргументов шаблона и u
шаблонов. В качестве рекомендации по написанию кода в примере кода также используются ссылки rvalue и forward
шаблон функции, поддерживающие идеальную пересылку. Дополнительные сведения см . в справочнике Rvalue: &>.
//C++11
template<typename T, typename U>
auto myFunc(T&& t, U&& u) -> decltype (forward<T>(t) + forward<U>(u))
{ return forward<T>(t) + forward<U>(u); };
//C++14
template<typename T, typename U>
decltype(auto) myFunc(T&& t, U&& u)
{ return forward<T>(t) + forward<U>(u); };
decltype
функции пересылки (C++11)
Функции пересылки создают программы-оболочек для вызовов других функций. Рассмотрим шаблон функции, который пересылает свои аргументы (или результаты выражения с этими аргументами) другой функции. Кроме того, функция пересылки возвращает результат вызова другой функции. В этом сценарии тип возвращаемого значения функции пересылки должен совпадать с типом возвращаемого значения функции в программе-оболочке.
В этом сценарии невозможно написать соответствующее выражение типа без decltype
описателя типов. Описатель decltype
типов включает универсальные функции пересылки, так как он не теряет необходимые сведения о том, возвращает ли функция ссылочный тип. Пример кода функции пересылки см. в предыдущем myFunc
примере шаблона функции.
Примеры
В следующем примере кода объявляется тип возвращаемого значения для шаблона Plus()
функции. Функция Plus
обрабатывает два операнда с перегрузкой operator+
. Таким образом, интерпретация оператора plus (+
) и возвращаемого типа Plus
функции зависит от типов аргументов функции.
// decltype_1.cpp
// compile with: cl /EHsc decltype_1.cpp
#include <iostream>
#include <string>
#include <utility>
#include <iomanip>
using namespace std;
template<typename T1, typename T2>
auto Plus(T1&& t1, T2&& t2) ->
decltype(forward<T1>(t1) + forward<T2>(t2))
{
return forward<T1>(t1) + forward<T2>(t2);
}
class X
{
friend X operator+(const X& x1, const X& x2)
{
return X(x1.m_data + x2.m_data);
}
public:
X(int data) : m_data(data) {}
int Dump() const { return m_data;}
private:
int m_data;
};
int main()
{
// Integer
int i = 4;
cout <<
"Plus(i, 9) = " <<
Plus(i, 9) << endl;
// Floating point
float dx = 4.0;
float dy = 9.5;
cout <<
setprecision(3) <<
"Plus(dx, dy) = " <<
Plus(dx, dy) << endl;
// String
string hello = "Hello, ";
string world = "world!";
cout << Plus(hello, world) << endl;
// Custom type
X x1(20);
X x2(22);
X x3 = Plus(x1, x2);
cout <<
"x3.Dump() = " <<
x3.Dump() << endl;
}
Plus(i, 9) = 13
Plus(dx, dy) = 13.5
Hello, world!
x3.Dump() = 42
Visual Studio 2017 и более поздних версий: компилятор анализирует decltype
аргументы, когда шаблоны объявляются вместо создания экземпляров. Таким образом, если не зависящая специализация найдена в decltype
аргументе, она не будет отложена до времени создания экземпляра; она обрабатывается немедленно и все результирующий ошибки диагностируются в то время.
В следующем примере показана такая ошибка компилятора, возникающая во время объявления.
#include <utility>
template <class T, class ReturnT, class... ArgsT> class IsCallable
{
public:
struct BadType {};
template <class U>
static decltype(std::declval<T>()(std::declval<ArgsT>()...)) Test(int); //C2064. Should be declval<U>
template <class U>
static BadType Test(...);
static constexpr bool value = std::is_convertible<decltype(Test<T>(0)), ReturnT>::value;
};
constexpr bool test1 = IsCallable<int(), int>::value;
static_assert(test1, "PASS1");
constexpr bool test2 = !IsCallable<int*, int>::value;
static_assert(test2, "PASS2");
Требования
Visual Studio 2010 или более поздней версии.
decltype(auto)
требуется Visual Studio 2015 или более поздней версии.