更新時間:2021-08-12 12:14:12 來源:動力節點 瀏覽1056次
定義可以在編譯時計算的表達式。
此類表達式可用作非類型模板參數、數組大小以及其他需要常量表達式的上下文,例如
整數n = 1 ;
std:: array < int , n > a1 ; // 錯誤:n 不是常量表達式
const int cn = 2 ;
std:: array < int , cn > a2 ; // OK: cn 是一個常量表達式
一個核心常量表達式是任何表達式,其評價不會評估以下情形之一:
的this指針,除了在constexpr功能正被評估作為表達式的一部分
調用未聲明為constexpr的函數(或構造函數)的函數調用表達式
constexpr int n = std:: numeric_limits < int > :: max ( ) ; // OK: max() 是 constexpr
constexpr int m = std:: time ( nullptr ) ; // 錯誤:std::time() 不是 constexpr
對constexpr已聲明但未定義的函數調用
對constexpr函數/構造函數模板實例化的函數調用,其中實例化無法滿足constexpr 函數/構造函數要求。
(C++20 起)對 constexpr 虛函數的函數調用,在常量表達式中不可使用的對象上調用,并且其生命周期開始于該表達式之外。
超出實現定義限制的表達式
一個表達式,其求值會導致任何形式的核心語言未定義行為(包括有符號整數溢出、被零除、數組邊界外的指針運算等)。未指定是否檢測到標準庫未定義行為。
constexpr 雙d1 = 2.0 / 1.0 ; // OK
constexpr double d2 = 2.0 / 0.0 ; // 錯誤:未定義
constexpr int n = std:: numeric_limits < int > :: max ( ) + 1 ; // 錯誤:溢出
int x, y, z [ 30 ] ;
constexpr 自動e1 = & y - & x ; // 錯誤:未定義的
constexpr auto e2 = & z [ 20 ] - & z [ 3 ] ; // OK
constexpr std:: bitset < 2 > a ;
constexpr bool b = a [ 2 ] ; // UB,但未指定是否檢測到
(直到 C++17)一個lambda 表達式
應用于聯合或其子對象的非活動成員的左值到右值隱式轉換或修改(即使它與活動成員共享公共初始序列)
(C++20 起)應用于具有不確定值的對象的左值到右值隱式轉換
為其活動成員(如果有)是可變的聯合調用隱式定義的復制/移動構造函數或復制/移動賦值運算符,除非聯合對象的生命周期在此表達式的計算中開始
(C++17 起) (C++20 前)賦值表達式或重載賦值運算符的調用將改變聯合的活動成員
引用變量或引用類型數據成員的id 表達式,除非該引用可用于常量表達式或其生命周期在此表達式的計算中開始
從簡歷轉換 無效* 任何指向對象類型的指針
(直到 C++20)dynamic_cast
reinterpret_cast
(直到 C++20)偽析構函數調用
(C++14 前)自增或自減運算符
(C++14 起)對象的修改,除非該對象具有非易失性文字類型并且其生命周期在表達式的求值內開始
constexpr int incr ( int & n ) {
return ++ n ;
}
constexpr int g ( int k ) {
constexpr int x = incr ( k ) ; // 錯誤:incr(k) 不是核心常量
// 表達式,因為 k 的生命周期
// 開始于表達式 incr(k) 之外
return x ;
}
constexpr int h ( int k ) {
int x= incr ( k ) ; // OK: x 不需要用核心初始化
// 常量表達式
return x ;
}
constexpr int y = h ( 1 ) ; // OK:用值 2 初始化 y
// h(1) 是一個核心常量表達式,因為
// k 的生命周期從表達式 h(1) 內部開始
(直至C ++ 20)一個typeid施加到多態型的一個glvalue表達
一個new-expression ,除非選定的分配函數是一個可替換的全局分配函數并且分配的存儲在此表達式的計算中被釋放 (C++20 起)
一個delete-expression ,除非它解除分配在此 expession 的計算中分配的存儲區域 (C++20 起)
(C++20 起)對std::allocator::allocate的調用,除非已分配的存儲在此表達式的計算中被釋放
(C++20 起)對std::allocator::deallocate的調用,除非它解除分配在此 expession 求值內分配的存儲區域
(因為C ++ 20)的AWAIT表達或產量表達
(因為C ++ 20)一個三通比較時的結果是不確定的
結果未指定時的等式或關系運算符
(C++14 前)賦值或復合賦值運算符
拋出表達式
(因為C ++ 20)的ASM-聲明
(因為C ++ 14)所述的調用的va_arg宏時,的調用是否的va_start宏可以評估是未指定的
(C++20 起)會拋出異常的dynamic_castortypeid表達式
在 lambda 表達式內部,this對該 lambda 外部定義的變量的引用或引用,如果該引用將是 odr 使用
void g ( ) {
const int n = 0 ;
constexpr int j = * & n ; // OK:在 lambda 表達式之外
[ = ] { constexpr int i = n ; // OK: 'n' 不是 odr 使用的,也沒有在這里捕獲。
constexpr int j = * & n ; // 格式錯誤:'&n' 將是 'n' 的 odr 使用。
} ;
}
甲常量表達式是任一
左值 (C++14 前)泛 左值(C++14起)核心常量表達式,它指的是
具有非臨時靜態存儲持續時間的對象,或
具有靜態存儲持續時間的臨時對象,但其值滿足以下純右值的約束,或
(C++14 起)
一個非即時 (因為C ++ 20)功能
一個純右值核心常量表達式,其值滿足以下約束:
如果該值是類類型的對象,引用類型的每個非靜態數據成員是指實體滿足用于約束的左值 (直到C ++ 14) glvalues (因為C ++ 14)以上
如果值是指針類型,它持有
具有靜態存儲期的對象的地址
超過具有靜態存儲持續時間的對象末尾的地址
一的地址非即時 (因為C ++ 20)功能
空指針值
如果值是指向成員函數的指針類型,則不指定立即函數
(C++20 起)
如果值是類或數組類型的對象,則每個子對象都滿足這些值的約束
積分常數表達式
整型常量表達式是隱式轉換為純右值的整型或無作用域枚舉類型的表達式,其中轉換后的表達式為核心常量表達式。如果在需要整型常量表達式的地方使用類類型的表達式,則該表達式會在上下文中隱式轉換為整型或無作用域枚舉類型。
以下上下文需要整數常量表達式:
數組邊界
new 表達式中除第一個以外的 維度
(直到 C++14)
位域長度
基礎類型不固定時的枚舉初始值設定項
對齊方式。
轉換后的常量表達式
甲轉換常量表達式類型T是一個表達式隱式轉換為類型T,其中,所述轉換后的表達式是一個常量表達式,并且隱式轉換序列只包含:
constexpr 用戶定義的轉換(因此可以在需要整數類型的地方使用類)
左值到右值的轉換
積分促銷
非縮小積分轉換
以下表達式或轉換可能是常量評估:
明顯的常量評估表達式
潛在評估表達式
花括號初始化器列表的直接子表達式(可能需要不斷評估以確定轉換是否正在縮小)
address-of (unary &) 出現在模板化實體中的表達式(可能需要不斷求值來確定這樣的表達式是否依賴于值)
上述之一的子表達式不是嵌套未計算操作數的子表達式
如果函數是constexpr 函數并由可能是常量求值的表達式命名,則需要該函數進行常量求值。
如果變量是constexpr 變量,或者是非易失性 const 限定的整數類型或引用類型,并且表示它可能是常量評估的id 表達式,則需要一個變量來進行常量評估。
一個默認的功能和實例化的定義函數模板專業化或可變模板專業化 (因為C ++ 14)如果該功能被觸發的或可變的 (因為C ++ 14)需要用于恒定評估。
以上就是動力節點小編介紹的"常量表達式詳解",希望對大家有幫助,想了解更多可查看Java在線學習。動力節點在線學習教程,針對沒有任何Java基礎的讀者學習,讓你從入門到精通,主要介紹了一些Java基礎的核心知識,讓同學們更好更方便的學習和了解Java編程,感興趣的同學可以關注一下。
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習