decltype (C++)

Описатель decltype типа возвращает тип указанного выражения. Описатель decltype типов вместе с auto ключевым словом полезен в первую очередь разработчикам, которые пишут библиотеки шаблонов. Используйте auto и decltype объявите функцию шаблона, тип возвращаемого значения которой зависит от типов аргументов шаблона. Кроме того, используйте auto и decltype объявите функцию шаблона, которая создает оболочку для вызова другой функции, а затем возвращает возвращаемый тип упаковаемой функции.

Синтаксис

decltype(expression)

Параметры

expression
Выражение. Дополнительные сведения см. в разделе "Выражения".

Возвращаемое значение

Тип параметра выражения .

Комментарии

Описатель decltype типов поддерживается в Visual Studio 2010 или более поздних версиях и может использоваться с машинным или управляемым кодом. decltype(auto) (C++ 14) поддерживается в Visual Studio 2015 и более поздних версиях.

Компилятор использует следующие правила для определения типа параметра выражения .

  • Если параметр выражения является идентификатором или доступом к члену класса, это тип сущности, decltype(expression) именуемой по выражению. Если такой сущности или параметра выражения нет набора перегруженных функций, компилятор выдает сообщение об ошибке.

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

  • Если параметр выражения является rvalue, decltype(expression) это тип выражения. Если параметр выражения является lvalue, decltype(expression) это ссылка на lvalue типа выражения.

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

auto( function_name parametersoptoptoptexpressionopt) function_body)constvolatile->decltype(noexcept{};

В следующем примере кода поздно заданный возвращаемый тип функции шаблона 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 или более поздней версии.