c++中的constexpr:html
1. 編譯時肯定和運行時肯定: 編譯時肯定如 const int a = 3; 運行時肯定如 const int b = func(); 其中a就是編譯時肯定,b是運行時肯定;c++
可是當func()的函數實現是 func(){return 3;},返回的是一個常量值,這個時候若是用const來接收,依然是運行時肯定,若是用constexpr來接收這個函數返回值,constexpr int b = func(); 在編譯階段編譯器就能夠肯定其常量屬性。數組
constexpr顯示的告訴編譯器,這個值是常量的。可是若是func的函數內返回的不是常量,constexpr int func(){ return func2(); } func2返回一個變量值,這個時候雖然指定了constexpr,可是肯定常量值的時間依然會推遲到運行時。函數
constexpr的做用:將常量表達式的常量值信息提早到編譯階段確認。優化
2.constexpr修飾的指針表示的是頂層指針,對指針有效。ui
3.c++11 指定函數返回值和參數必須保證是字面量,而且只有一個return, 不能是虛函數;c++14 相對於c++11沒必要保證只有一個retuan;(一個return的函數在複雜狀況下能夠用三元運算符或者遞歸計算來返回值)spa
const和constexpr修飾變量時:const表達式能夠在運行時再肯定常量屬性,constexpr修飾的表達式在編譯器肯定常量屬性(常量的值)。.net
const和constexpr修飾函數時:constexpr函數參數若是不能在編譯器肯定常量屬性,則至關於const設計
const和constexpr修飾類時:儘管構造函數不能是const的,可是字面值常量類的構造函數能夠是constexpr函數。事實上,一個字面值常量類必須至少提供一個constexpr構造函數。指針
constexpr構造函數能夠聲明成=default的形式(或者是刪除函數的形式)。不然,constexpr構造函數就必須既符合構造函數的要求(意味着不能包含返回語句),又符合constexpr函數的要求(意味着它能擁有的惟一可執行語句就是返回語句)。
綜合這兩點可知,constexpr構造函數體通常來講應該是空的,所以對函數成員的初始化必須放在初始化列表中。constexpr構造函數必須初始化全部數據成員,constexpr構造函數保證了傳遞給它的全部參數都是constexpr類型的,產生的對象的全部成員也都是constexpr
參考地址:https://www.jianshu.com/p/34a2a79ea947
https://blog.csdn.net/qq_37653144/article/details/78518071
如下內容轉: http://www.javashuo.com/article/p-oyucyfrc-ct.html
Scott Meyers在effective modern c++中提到「If there were an award for the most confusing new word in C++11, constexpr would probably win it.」
因而可知,constexpr確實是比較難以讓人理解。加之其在C++11和14中的標準略有不一樣,也加重了這種難度。
參考幾本經典教材(C++ primer, effective modern C++, a tour of C++)以及藍色大大在知乎上的一些解答,整理出constexpr的用法和注意事項。
1.概念,constexpr objects
C++ primer中給出的定義是 「常量表達式是指不會改變而且在編譯過程當中就能獲得計算結果的表達式 【1】。」
能夠理解爲在const上又加一層限定條件,即const並不限定是編譯期常量仍是運行期常量,而constexpr必須是編譯期常量(在編譯階段獲得結果)。
舉例以下:
衆所周知,array的size是須要在編譯期肯定的,因此當其size不是一個常量表達式時,是沒法經過編譯的。
int i; const int size = i; int arr[size]; //error,size不是常量表達式,不能在編譯期肯定
而若是size是一個constexpr變量,則符合編譯期肯定的條件,能夠經過編譯。
constexpr auto size = 10; int arr[size]; //OK,size時常量表達式
固然,要定義一個常量表達式的時候,也要確保其右側是常量表達式,不然該處便沒法經過編譯。
int i; constexpr int size = i; // error,i不能在編譯期肯定
因此用effective modern c++中的一句話總結這一部分就是:
「constexpr objects are const and are initialized with values known during compilation【2】」.
2. constexpr functions
比起constexpr變量,用constexpr修飾的函數有些更容易混淆的地方。
1) constexpr修飾的函數,當傳入參數是能夠在編譯期計算出來時,產生constexpr變量;當傳入參數不能夠在編譯期計算出來時,產生運行期遍歷(constexpr等於不存在)。
所以,沒必要寫兩個函數,若是函數體存在constexpr適用條件,就應該加上constexpr關鍵字。
例如(例子來源【3】):
constexpr int foo(int i) { return i + 5; } int main() { int i = 10; std::array<int, foo(5)> arr; // OK,5是常量表達式,計算出foo(5)也是常量表達式 foo(i); // Call is Ok,i不是常量表達式,但仍然能夠調用(constexpr 被忽略) std::array<int, foo(i)> arr1; // Error,可是foo(i)的調用結果不是常量表達式了 }
2) 在C++11和14中的區別
在C++11標準中,對於constexpr修飾的函數給了及其苛刻的限定條件:函數的返回值類型及全部形參的類型都是字面值類型,並且函數體內必須有且只有一條return語句【1】。
這個條件顯然是太苛刻了,以致於不少在constexpr的操做都要藉助?:表達式,遞歸等辦法實現。
在C++14中,放寬了這一限定,只保留了「函數的返回值類型及全部形參的類型都是字面值類型」,也就是說,這些值都在編譯期能肯定了就行。
3. constexpr class(字面值常量類)
built-in類型是字面值常量,可是有時須要自定義類型也做爲字面值常量,這時候就需須要將constexpr修飾構造函數。
字面值常量類必須至少提供一個constexpr構造函數。
例如:
class Point { public: constexpr Point(double xval = 0, double yval = 0): x(xval), y(yval) { } constexpr double getX() const {return x;} constexpr double getY() const {return y;} private: double x,y; };
當這樣定義一個類後,即可以將Point類型的對象定義爲字面值常量。即:
constexpr Point p1(9.4, 27,7); constexpr Point p2(28.8, 5.3); constexpr Point midpoint(const Point& p1, const Point& p2) { return {p1.getX() + p2.getX() / 2, p1.getY() + p2.getY() / 2} ; } constexpr auto mid = midpoint (p1, p2);
上述例子中,p1,p2均爲字面值常量,midpoint爲constexpr修飾的函數,因此求取mid的整個過程均在編譯期就能夠完成,軟件運行的時間天然會大大減小。
至此關於constexpr的三個主要用途(constexpr變量,constexpr修飾函數,constexpr修飾構造函數)就總結完畢,下面是一些注意事項。
注意事項1: 不少人(包括我本身)在gcc中驗證數組大小必須在編譯期指定的例子時發現:
若是array定義在主函數內,即便給定的不是一個常量表達式,也能夠經過編譯。這差點顛覆了個人認知。。。
藍色大大在知乎答案【4】中解釋了這一點,實際上是C99中的variable length array。在全局變量中不能使用(沒法分配內存),在局部變量中可使用,細節能夠參考那份解答。
注意事項2:constexpr這麼複雜,到底爲何要用?
其實第一仍是爲了效率。效率是C++的設計哲學之一,編譯期能夠肯定的東西,即可以提醒編譯期優化,也可能存放在read-only memory中
第二就是這樣聲明的constexpr變量即可以用在諸如上述數組長度指定,還有包括模板參數,case標籤等場合,會便於使用【5】。
參考資料:
1. Stanley B. Lippman / Josée Lajoie / Barbara E. Moo, C++ Primer 中文版(第 5 版)[M]. 電子工業出版社,2013
2. Meyers S. Effective Modern C++[M]. O'Reilly, 2014.
3. 藍色在知乎問題「C++ const 和 constexpr 的區別?」中的解答: https://www.zhihu.com/question/35614219
4. 藍色在知乎問題「constexpr和const數組的區別?」中的解答: https://www.zhihu.com/question/29662350/answer/45192834
5. Stroustrup B. A Tour of C++[M]. Addison-Wesley Longman, Amsterdam, 2013.