c++11 constexptr和常量表達式
常量表達式是指值不會改變並且在編譯過程中就能得到計算結果的表示式。
編譯過程中得到計算結果。
字面值屬於常量表達式,用常量表達式初始化的const物件也是常量表達式。
一個物件(或表示式)是不是常量表達式由它的資料型別和初始值共同決定。
(注意!!!)對於這條語句:const int sz = get_size();,sz本身是常量,但它的具體值直到執行時才能獲得,不是常量表達式。
#include<iostream> using namespace std; int main(int argc, char* argv[]) { const int max_files = 20; //max_files是常量表達式 const int limit = max_files + 1; //limit是常量表達式 int staff_size = 27; //staff_size不是常量表達式,資料型別只是普通型別而非常量型別 const int sz = get_size(); //重要!!!sz本身是常量,但它的具體值直到執行時才能獲得,不是常量表達式 }
constexpr變數
在一個複雜的系統中,很難分辨一個初始值到底是不是常量表達式。當然可以定義一個const變數並把它的初始值設為我們認為的某個常量表達式,但在實際使用時,儘管要求如此卻常常發現初始值並非常量表達式的情況(例如上述的const int sz = get_size(); 語句)。
C++11新標準規定,允許將變數宣告為constexpr型別以便由編譯器來驗證變數的值是否是一個常量表達式。宣告為constexpr的變數一定是一個常量,而且必須用常量表達式初始化:
#include<iostream> using namespace std; int main(int argc, char* argv[]) { constexpr int max_files = 20; //20是常量表達式 constexpr int limit = max_files + 1; //max_files + 1是常量表達式 constexpr int sz = size(); //重要!!!只有當size是一個constexpr函式時,才是一條正確的宣告語句}
儘管不能使用普通函式作為constexpr變數的初始值,但可以通過constexpr函式(編譯時就可以計算其結果)初始化constexpr變數。
constexpr函式
constexpr函式是指用於常量表達式的函式。
遵循以下規定:(1)函式的返回型別以及所有形參的型別都得是字面值型別;(2)函式體中必須只有一條return語句。
#include<iostream> using namespace std; constexpr int new_sz() { return 42; } int main(int argc, char* argv[]) { constexpr int foo = new_sz(); cout << foo << endl; //42 getchar(); return 0; }
分析:我們把new_sz定義成無參的constexpr函式。因為編譯器能在程式編譯時驗證new_sz函式返回的是常量表達式,所以可以用new_sz函式初始化constexpr型別的變數foo。
執行該初始化任務時,編譯器把對constexpr函式的呼叫替換成其結果值。為了在編譯過程中隨時展開,constexpr函式被隱式地指定為行內函數。
constexpr函式體內也可以含有其他語句,只要這些語句在執行時不執行任何操作就行(求解答?)。例如,constexpr函式中可以有空語句、類型別名以及using宣告。
constexpr int size() { //返回值型別為字面值型別 ; //空語句 using In = int; //using宣告 typedef int INT; //類型別名 return 10; }
我們允許constexpr函式的返回值並非一個常量。當scale的實參是常量表達式,它的返回值也是常量表達式,反之則不然:
#include<iostream> using namespace std; constexpr int size() { ; using namespace std; typedef int INT; return 10; } constexpr int new_sz() { return 42; } //如果arg是常量表達式,則scale(arg)也是常量表達式 constexpr size_t scale(size_t cnt) { return new_sz()*cnt; } int main(int argc, char* argv[]) { int arr[scale(2)]; //正確 //int i = 2; //int arr2[scale(i)]; //錯誤:scale(i)不是常量表達式 const int j = 2; int arr3[scale(j)]; //正確 getchar(); return 0; }
把行內函數和constexpr函式放在標頭檔案中:
和其他函式不一樣,行內函數和constexpr函式可以在程式中多次定義。畢竟,編譯器要想展開函式僅有函式宣告是不夠的,還需要函式的定義。不過,對於某個給定的行內函數或者constexpr函式來說,它的多個定義必須完全一致。基於這個原因,行內函數和constexpr函式通常定義在標頭檔案中。
指標和constexpr
在constexpr宣告中如果定義了一個指標,限定符constexpr僅對指標有效,與指標所指的物件無關:
const int *p = nullptr; //p是一個指向整型常量的指標 constexpr int *q = nullptr; //q是一個指向整型的常量指標
分析:p和q的型別相差甚遠,p是一個指向常量的指標,q是一個常量指標,其中關鍵在於constexpr把它所定義的物件置為頂層const。
————————————————
版權宣告:本文為CSDN博主「傻月菇涼」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本宣告。
原文連結:https://blog.csdn.net/weixin_40087851/article/details/82754189