C++ 11 新特性: constexpr变量和constexpr函数
constexpr變量
字面值類型包括算術類型、引用、指針、枚舉和數據成員都是字面值類型的聚合類。
聚合類的定義:
??? 所有成員都是public的。
??? 沒有定義任何構造函數。
??? 沒有類內初始值。
??? 沒有基類,也沒有虛函數。
如:
struct Data {
?? ?int ival;
?? ?string str;
};
??? 1
??? 2
??? 3
??? 4
如果一個類不是聚合類,但它符合下述要求,則它也是一個字面值常量類:
??? 數據成員必須是字面值類型
??? 類必須有一個constexpr構造函數
??? 如果一個數據成員含有類內初始值,則內置類型成員的初始值必須是一條常量表達式(其定義見下文);或者如果成員屬于某種類類型,則初始值必須使用成員自己的constexpr構造函數
??? 類必須使用構造函數的默認定義
常量表達式是指值不會改變并且在編譯過程就能得到計算結果的表達式。字面值屬于常量表達式,用常量表達式初始化的const對象也是常量表達式。
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不是常量表達式
??? 1
??? 2
??? 3
??? 4
??? 5
盡管staff_size的初始始是個字面值常量,但由于它的數據類型非const,所以它不是常量表達式。盡管sz本身是一個常量,但它的具體值直到運行時才能得到,也不是常量表達式。
在一個復雜的系統中,很難分辨一個初始值到底是不是常量表達式。當然可以定義一個const變量并把它的初始值設為我們認為的某個常量表達式,但在實際使用中,盡管要求如此卻常常發現初始值并非常量表達式的情況。
C++11規定,允許將變量聲明為constexpr類型以便由編譯器來驗證變量的值是否是一個常量表達式。聲明為constexpr的變量一定是一個常量,而且必須用常量表達式初始化。
constexpr int mf=20;?? ??? ?//20是常量表達式
constexper int limit=mf+1;?? ?//mf+1是常量表達式
constxper int sz=size();?? ?//只有當size是一個constxper函數時才是一條正確的聲明語句
??? 1
??? 2
??? 3
不能用普通函數作為constexpr變量的初始值,只能用constexpr函數去初始化constexpr變量。這種函數足夠簡單,以使得編譯時就可以計算其結果。
一般來說,如果你認定變量是一個常量表達式,那就把它聲明成constexpr類型。
constexpr函數
constexpr函數是指能用于常量表達式的函數。該函數要遵循幾項約定:函數的返回類型及所有形參的類型都得是字面值類型,而且函數體中必須有且只有一條return語句:
constexpr int new_sz() { return 42; }
constexpr int foo = new_sz();
??? 1
??? 2
在對變量foo初始化時,編譯器把對constexpr函數的調用替換成其結果值。為了能在編譯過程中隨時展開,constexpr函數被隱式地指定為內聯函數。
constexpr函數體內也可以包含其它語句,只要這些語句在運行時不執行任何操作就行。例如,constexpr函數中可以有空語句、類型別名以及using聲明。
需要注意的是,我們允許constexpr函數的返回值并非一個常量:
//如果arg是常量表達式,則scale(arg)也是常量表達式
constexpr size_t scale(size_t cnt){ return new_sz() * cnt; }
??? 1
??? 2
當scale的實參是常量表達式時,它的表達式也是常量表達式,反之則不然:
int arr[scale(2)];?? ?//正確:scale(2)是常量表達式
int i = 2;?? ??? ??? ?//i不是常量表達式
int a2[scale(i)];?? ?//錯誤:scale(i)不是常量表達式
??? 1
??? 2
??? 3
當把scale函數用在需要常量表達式的上下文中時,如果其結果恰好不是常量表達式,編譯器將發出錯誤信息。
注意,我們要把內聯函數和constexpr函數定義在頭文件中。因為內鏈函數是內部鏈接的,如果你在b.cpp中定義這個函數,那么在a.cpp中即使有這個函數聲明,但由于內聯函數是內部鏈接的,所以b.cpp不會提供其定義。所以在鏈接時a.obj無法找到這個函數的定義,便會出現無法解析的外部符號的錯誤
constexpr構造函數
我們知道,構造函數不能是const的。因為當我們創建一個類的const對象時,直到構造函數完成初始化過程,對象才能真正取得其”常量“屬性。因此,構造函數在const對象的構造過程中可以可以向其寫值。但是字面值常量類的構造函數可以是constexpr函數。事件上,一個字面值常量類必須至少提供一個constexpr函數。
constexpr構造函數可以聲明成=default的形式(或者是刪除函數的形式)。否則,constexpr構造函數體一般來說應該是空的,因為構造函數不能包含返回語句,而constexpr函數的唯一可執行語句就是返回語句。constexpr構造函數的聲明形式如下:
class Debug {
public:
?? ?constexpr Debug(int i) :i_(i) {}
private:
?? ?int i_;
};
??? 1
??? 2
??? 3
??? 4
??? 5
??? 6
constexpr構造函數必須初始化所有數據成員,初始值或者使用constexpr構造函數,或者是一條常量表達式。
————————————————
版權聲明:本文為CSDN博主「freshman94」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_22660775/article/details/89336997
總結
以上是生活随笔為你收集整理的C++ 11 新特性: constexpr变量和constexpr函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 内联函数的定义可能不止一次
- 下一篇: `constexpr`和`const`之