decltype (C++)decltype (C++)

Decltype类型说明符生成指定表达式的类型。The decltype type specifier yields the type of a specified expression. Decltype类型说明符一起使用auto 关键字,主要的开发人员编写模板库非常有用。The decltype type specifier, together with the auto keyword, is useful primarily to developers who write template libraries. 使用自动decltype声明模板函数的返回类型取决于其模板自变量的类型。Use auto and decltype to declare a template function whose return type depends on the types of its template arguments. 或者,使用自动decltype声明包装对其他函数的调用,然后返回所包装的函数的返回类型的模板函数。Or, use auto and decltype to declare a template function that wraps a call to another function, and then returns the return type of the wrapped function.

语法Syntax

decltype( expression )

参数Parameters

参数Parameter 描述Description
表达式expression 一个表达式。An expression. 有关详细信息,请参阅表达式For more information, see Expressions.

返回值Return Value

类型表达式参数。The type of the expression parameter.

备注Remarks

Decltype类型说明符中 Visual c + + 2010年或更高版本,支持,可与本机或托管代码。The decltype type specifier is supported in Visual C++ 2010 or later versions, and can be used with native or managed code. Visual Studio 2015 及更高版本支持 decltype(auto) (C++14)。decltype(auto) (C++14) is supported in Visual Studio 2015 and later.

编译器使用以下规则来确定的类型表达式参数。The compiler uses the following rules to determine the type of the expression parameter.

  • 如果表达式参数是标识符或类成员访问decltype(expression)是命名的实体的类型表达式If the expression parameter is an identifier or a class member access, decltype(expression) is the type of the entity named by expression. 如果没有此类实体或表达式参数命名一组重载函数,则编译器将生成一条错误消息。If there is no such entity or the expression parameter names a set of overloaded functions, the compiler yields an error message.

  • 如果表达式参数是对函数或重载的运算符函数的调用decltype(expression)是该函数的返回类型。If the expression parameter is a call to a function or an overloaded operator function, decltype(expression) is the return type of the function. 将忽略重载运算符两边的括号。Parentheses around an overloaded operator are ignored.

  • 如果表达式参数是rvaluedecltype(expression)是一种表达式If the expression parameter is an rvalue, decltype(expression) is the type of expression. 如果表达式参数是左值decltype(expression)左值引用为的类型表达式If the expression parameter is an lvalue, decltype(expression) is an lvalue reference to the type of expression.

下面的代码示例演示的一些用途decltype类型说明符。The following code example demonstrates some uses of the decltype type specifier. 首先,假定已编码下列语句。First, assume that you have coded the following statements.

int var;
const int&& fx();
struct A { double x; }
const A* a = new A();

接下来,检查类型,返回的四个decltype下表中的语句。Next, examine the types that are returned by the four decltype statements in the following table.

语句Statement 类型Type 说明Notes
decltype(fx()); const int&& 右值引用const intAn rvalue reference to a const int.
decltype(var); intint 变量 var 的类型。The type of variable var.
decltype(a->x); doubledouble 成员访问的类型。The type of the member access.
decltype((a->x)); const double& 内部括号导致语句作为表达式而不是成员访问计算。The inner parentheses cause the statement to be evaluated as an expression instead of a member access. 而且由于a被声明为const指针,该类型是指const 双And because a is declared as a const pointer, the type is a reference to const double.

Decltype 和 AutoDecltype and Auto

在 C++ 14 中,你可以使用decltype(auto)不带尾随返回类型来声明其返回类型的模板函数取决于其模板自变量的类型。In C++14, you can use decltype(auto) with no trailing return type to declare a template function whose return type depends on the types of its template arguments.

在 C + + 11 中,可以使用decltype类型一起使用的尾随返回类型上的说明符自动关键字来声明其返回类型的模板函数取决于其模板的类型自变量。In C++11, you can use the decltype type specifier on a trailing return type, together with the auto keyword, to declare a template function whose return type depends on the types of its template arguments. 例如,考虑下面的代码示例,其中模板函数的返回类型取决于模板自变量类型。For example, consider the following code example in which the return type of the template function depends on the types of the template arguments. 在代码示例中,未知占位符指示不能指定返回类型。In the code example, the UNKNOWN placeholder indicates that the return type cannot be specified.

template<typename T, typename U>
UNKNOWN func(T&& t, U&& u){ return t + u; };

引入decltype类型说明符使开发人员若要获取模板函数返回的表达式类型。The introduction of the decltype type specifier enables a developer to obtain the type of the expression that the template function returns. 使用替代函数声明语法更高版本,显示自动关键字,并且decltype类型说明符来声明后指定返回类型。Use the alternative function declaration syntax that is shown later, the auto keyword, and the decltype type specifier to declare a late-specified return type. 后指定返回类型是在对声明进行编译而不是编码时确定的。The late-specified return type is determined when the declaration is compiled, instead of when it is coded.

以下原型阐述一个替代函数声明的语法。The following prototype illustrates the syntax of an alternative function declaration. 请注意, const易失性限定符,并且引发异常规范都是可选的。Note that the const and volatile qualifiers, and the throw exception specification are optional. Function_body占位符表示指定函数作用的复合语句。The function_body placeholder represents a compound statement that specifies what the function does. 作为最佳编码做法,表达式中的占位符decltype语句与指定的表达式应匹配返回语句,如果有,在function_bodyAs a best coding practice, the expression placeholder in the decltype statement should match the expression specified by the return statement, if any, in the function_body.

自动 function_name ( 参数选择 ) constopt 易失性opt -> *decltype (***表达式 ) 引发选择 { *function_body***};**auto function_name ( parametersopt ) constopt volatileopt -> decltype( expression ) throwopt { function_body };

在下面的代码示例中,myFunc 模板函数的后指定返回类型取决于 tu 模板自变量的类型。In the following code example, the late-specified return type of the myFunc template function is determined by the types of the t and u template arguments. 作为最佳编码做法,此代码示例还使用右值引用和forward函数模板来支持完美转发As a best coding practice, the code example also uses rvalue references and the forward function template, which support perfect forwarding. 有关详细信息,请参阅右值引用声明符:&&For more information, see Rvalue Reference Declarator: &&.

//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 and Forwarding Functions (C++11)

转发函数包装对其他函数的调用。Forwarding functions wrap calls to other functions. 请考虑将其自变量或包含这些自变量的表达式的结果转发到其他函数的函数模板。Consider a function template that forwards its arguments, or the results of an expression that involves those arguments, to another function. 此外,转发函数返回调用其他函数的结果。Furthermore, the forwarding function returns the result of calling the other function. 在此方案中,转发函数的返回类型应与包装函数的返回类型相同。In this scenario, the return type of the forwarding function should be the same as the return type of the wrapped function.

在此方案中,您无法编写适当的类型表达式而无需decltype类型说明符。In this scenario, you cannot write an appropriate type expression without the decltype type specifier. Decltype类型说明符将启用泛型转发函数,因为它不会丢失有关函数是否返回引用类型所需的信息。The decltype type specifier enables generic forwarding functions because it does not lose required information about whether a function returns a reference type. 有关转发函数的代码示例,请参阅上面的 myFunc 模板函数示例。For a code example of a forwarding function, see the previous myFunc template function example.

示例Example

下面的代码示例声明模板函数 Plus() 的后指定返回类型。The following code example declares the late-specified return type of template function Plus(). Plus函数将处理与两个操作数operator + 重载。The Plus function processes its two operands with the operator+ overload. 因此,对 Plus 函数的加运算符 (+) 和返回类型的解释取决于函数自变量的类型。Consequently, the interpretation of the plus operator (+) and the return type of the Plus function depends on the types of the function arguments.

// 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

示例Example

Visual Studio 2017 和更高版本: 编译器模板是声明而实例化时分析 decltype 参数。Visual Studio 2017 and later: The compiler parses decltype arguments when the templates are declared rather than instantiated. 因此,如果在 decltype 参数中找到非依赖专用化,则它不会被推迟到实例化时间,而会被立即处理,并且将在此时诊断产生的所有错误。Consequently, if a non-dependent specialization is found in the decltype argument, it will not be deferred to instantiation-time and will be processed immediately and any resulting errors will be diagnosed at that time.

以下示例显示了在声明时引发的这类编译器错误:The following example shows such a compiler error that is raised at the point of declaration:

#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 C++ 2010 或更高版本。Visual C++ 2010 or later versions.

decltype(auto) 需要 Visual Studio 2015 或更高版本。decltype(auto) requires Visual Studio 2015 or later.