名稱空間
變體
操作

decltype 說明符 (C++11 起)

來自 cppreference.com
< cpp‎ | 語言
 
 
C++ 語言
 
 

檢查實體或表示式的宣告型別和值類別。

目錄

[編輯] 語法

decltype ( 實體 ) (1)
decltype ( 表示式 ) (2)

[編輯] 解釋

1) 如果引數是未加括號的id-表示式或未加括號的類成員訪問表示式,則 decltype 產生該表示式所命名的實體的型別。如果沒有這樣的實體,或者如果引數命名了一組過載函式,則程式格式不正確。

如果引數是命名結構化繫結的未加括號的id-表示式,則 decltype 產生引用型別(在結構化繫結宣告的規範中描述)。

(C++17 起)

如果引數是命名非型別模板引數的未加括號的id-表示式,則 decltype 產生模板引數的型別(在模板引數聲明瞭佔位符型別的情況下,執行任何必要的型別推導之後)。即使實體是模板引數物件(一個 const 物件),該型別也是非 const 的。

(C++20 起)
2) 如果引數是型別為 T 的任何其他表示式,並且
a) 如果表示式值類別xvalue,則 decltype 產生 T&&
b) 如果表示式的值類別是lvalue,則 decltype 產生 T&
c) 如果表示式的值類別是prvalue,則 decltype 產生 T

如果表示式是返回類型別純右值的函式呼叫,或是其右運算元是此類函式呼叫的逗號表示式,則不為該純右值引入臨時物件。

(C++17 前)

如果表示式是純右值(除了 (可能加括號的) 即時呼叫(C++20 起),則不會從該純右值具體化臨時物件:這樣的純右值沒有結果物件。

(C++17 起)
由於不建立臨時物件,因此型別無需完整或具有可用的解構函式,並且可以是抽象的。此規則不適用於子表示式:在 decltype(f(g())) 中,g() 必須具有完整型別,但 f() 則不必。

請注意,如果物件的名稱被括號括起來,它將被視為普通的左值表示式,因此 decltype(x)decltype((x)) 通常是不同的型別。

decltype 在宣告難以或不可能使用標準符號宣告的型別時非常有用,例如與 lambda 相關的型別或依賴於模板引數的型別。

[編輯] 注意

功能測試宏 標準 特性
__cpp_decltype 200707L (C++11) decltype

[編輯] 關鍵詞

decltype

[編輯] 示例

#include <cassert>
#include <iostream>
#include <type_traits>
 
struct A { double x; };
const A* a;
 
decltype(a->x) y;       // type of y is double (declared type)
decltype((a->x)) z = y; // type of z is const double& (lvalue expression)
 
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) // return type depends on template parameters
                                      // return type can be deduced since C++14
{
    return t + u;
}
 
const int& getRef(const int* p) { return *p; }
static_assert(std::is_same_v<decltype(getRef), const int&(const int*)>);
auto getRefFwdBad(const int* p) { return getRef(p); }
static_assert(std::is_same_v<decltype(getRefFwdBad), int(const int*)>,
    "Just returning auto isn't perfect forwarding.");
decltype(auto) getRefFwdGood(const int* p) { return getRef(p); }
static_assert(std::is_same_v<decltype(getRefFwdGood), const int&(const int*)>,
    "Returning decltype(auto) perfectly forwards the return type.");
 
// Alternatively:
auto getRefFwdGood1(const int* p) -> decltype(getRef(p)) { return getRef(p); }
static_assert(std::is_same_v<decltype(getRefFwdGood1), const int&(const int*)>,
    "Returning decltype(return expression) also perfectly forwards the return type.");
 
int main()
{
    int i = 33;
    decltype(i) j = i * 2;
    static_assert(std::is_same_v<decltype(i), decltype(j)>);
    assert(i == 33 && 66 == j);
 
    auto f = [i](int av, int bv) -> int { return av * bv + i; };
    auto h = [i](int av, int bv) -> int { return av * bv + i; };
    static_assert(!std::is_same_v<decltype(f), decltype(h)>,
        "The type of a lambda function is unique and unnamed");
 
    decltype(f) g = f;
    std::cout << f(3, 3) << ' ' << g(3, 3) << '\n';
}

輸出

42 42

[編輯] 參考

擴充套件內容
  • C++23 標準 (ISO/IEC 14882:2024)
  • 9.2.9.5 Decltype 說明符 [dcl.type.decltype]
  • C++20 標準 (ISO/IEC 14882:2020)
  • 9.2.8.4 Decltype 說明符 [dcl.type.decltype]
  • C++17 標準 (ISO/IEC 14882:2017)
  • 待定 Decltype 說明符 [dcl.type.decltype]
  • C++14 標準 (ISO/IEC 14882:2014)
  • 待定 Decltype 說明符 [dcl.type.decltype]
  • C++11 標準 (ISO/IEC 14882:2011)
  • 待定 Decltype 說明符 [dcl.type.decltype]

[編輯] 參見

auto 說明符 (C++11) 指定從表示式推導的型別 [編輯]
(C++11)
獲取模板型別引數物件的引用,用於未求值上下文
(函式模板) [編輯]
(C++11)
檢查兩個型別是否相同
(類模板) [編輯]
C 文件 for typeof