decltype (C++)

型別 decltype 規範會產生指定表達式的類型。 型 decltype 別規範與 auto 關鍵詞一起,主要適用於撰寫範本連結庫的開發人員。 使用 autodecltype 來宣告其傳回型別相依於其樣板自變數類型的函式範本。 或者,使用 autodecltype 宣告包裝對另一個函式呼叫的函式範本,然後傳回包裝函式的傳回型別。

語法

decltype( expression )

參數

expression
運算式。 如需詳細資訊,請參閱 表達式

傳回值

expression 參數的類型。

備註

decltype Visual Studio 2010 或更新版本中支援類型規範,而且可以搭配原生或 Managed 程式代碼使用。 Visual Studio 2015 和更新版本支援 decltype(auto) (C++14)。

編譯程式會使用下列規則來判斷參數的類型 expression

  • expression如果參數是標識碼或類別成員存取decltype(expression)則 為所expression命名實體的類型。 如果沒有這類實體或 expression 參數會命名一組多載函式,編譯程式會產生錯誤訊息。

  • expression如果參數是函式或多載運算元函式的呼叫,decltype(expression)則 為函式的傳回型別。 在多載運算子周圍的括號會被忽略。

  • expression如果參數是右值decltype(expression)則 為的型別expressionexpression如果參數是左值decltype(expression)則 為類型的expression左值參考

下列程式代碼範例示範型別規範的 decltype 一些用法。 首先,假設您已撰寫下列語句的程序代碼。

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

接下來,檢查下表中四 decltype 個 語句所傳回的類型。

陳述式 類型 備註
decltype(fx()); const int&& 的右值參考const int
decltype(var); int 變數 var 的類型。
decltype(a->x); double 成員存取的類型。
decltype((a->x)); const double& 括號內的陳述式會評估為運算式而不是成員存取。 而且,因為 a 宣告為 const 指標,因此類型是 的 const double參考。

decltypeauto

在 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 限定符,以及例外狀況規格是選擇性的throwvolatilefunction_body 位元代表複合語句,指定函式的作用。 作為最佳編碼作法,expression語句中的decltype佔位元應該符合 語句所return指定的運算式,如果有的話。function_body

autofunction_name(parametersopt optoptvolatiledecltype(expression)->noexcept)const{function_body};

在下列程式代碼範例中,函式範本的myFunc晚期指定傳回類型取決於和 u 樣板自變數的類型t。 作為最佳編碼作法,程式代碼範例也會使用右值參考和 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 傳回型別的解譯取決於函式自變數的類型。

// 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 或更新版本。