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 иvolatilethrowспецификация исключения являются необязательными. Заполнитель function_body представляет составную инструкцию, которая указывает, что выполняет функция. В качестве оптимальной методики expression написания кода заполнитель в decltype инструкции должен соответствовать выражению, указанному return оператором, если таковой function_bodyимеется.

autofunction_name(parameters)constopt optvolatile->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");

Requirements

Visual Studio 2010 или более поздней версии.

decltype(auto) требуется Visual Studio 2015 или более поздней версии.