decltype
(C++)
型別 decltype
規範會產生指定表達式的類型。 型 decltype
別規範與 auto
關鍵詞一起,主要適用於撰寫範本連結庫的開發人員。 使用 auto
和 decltype
來宣告其傳回型別相依於其樣板自變數類型的函式範本。 或者,使用 auto
和 decltype
宣告包裝對另一個函式呼叫的函式範本,然後傳回包裝函式的傳回型別。
語法
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)
則 為的型別expression
。expression
如果參數是左值,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 參考。 |
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
限定符,以及例外狀況規格是選擇性的throw
。volatile
佔 function_body
位元代表複合語句,指定函式的作用。 作為最佳編碼作法,expression
語句中的decltype
佔位元應該符合 語句所return
指定的運算式,如果有的話。function_body
auto
function_name
(
parameters
opt optoptvolatile
decltype(
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 或更新版本。
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應