總覽
constexpr
修飾變量,變量必須在執行前確認.
修飾函數,表示入參和出參可能在編譯前確認.
函數
constexpr
修飾的函數裏面的都應該是constexpr
.讓編程更加靈活.如果不是,就可以值能普通函數用.
返回值不是
const
,僅僅用於修飾.變量
const
類型的變量,執行前確認值.可能放在只讀區域.
constexpr
是const
的加強版.
constexpr
修飾的變量
核心
執行前必須能確認值.一般最晚鏈接前,共享庫可以是加載.即虛擬地址也是可以的.
constexpr
也是const
類型,不能改.const
的加強版本.編譯時明確的好處
數據可以存在只讀區.嵌入式開發感知更強.
可以用在需要完整常量表達式的場合. 還能做一下簡單計算.
編譯器使用場景
int main() { const int x = 5; int s[x]; }
指定數組長度.
#include <array> int main() { constexpr int len = sizeof(int); std::array<int,len> a; }
作爲模板參數.
#include <array> int main() { constexpr int len = sizeof(int); enum class T { START=len, MID, END }; }
給枚舉類型賦值.
#include <array> constexpr int len = sizeof(int); struct alignas(len) T { char s[10]; int a; }; int main() { T a; }
指定字節對齊
等等,其他場景都可以.
const
僅僅修飾變量不可變.
不要求編譯時知道.
constexpr
修飾的函數
核心
僅僅時修飾: 入參都是
constexpr
的時候可能會生成constexpr
的數據. 即編譯前知曉.傳入非
constexpr
類型的數據,則普通函數使用,返回值不是const
. 這裏和返回值類型無關.技巧
肯定可以輸出
constexpr
結果的函數,可以當成constexpr
修飾的變量使用.
B
內存總是A
內存的平方#include<array> constexpr int getSize(int n) { return n * n; } int main() { constexpr int len = 10; std::array<int,len> a; std::array<int,getSize(len)> b; }
模板類型必須在編譯時確認,就需要藉助
constexpr
.入參是
constexpr
,返回值也是.
c++11
和c++14
對constexpr
函數的限制
C++11
只允許有個return
.
C++14
可以有複雜的語句.
C++11
#include<array> template<typename T> void show(T&& t){ t.error(); } constexpr int getSize(int n) { return n ? getSize(n-1) + n : 0; } int main() { constexpr int len = 5; std::array<int,len> a; std::array<int,getSize(len)> b; show(b); }
採用遞歸和三元運算的方式將其複雜化.
這裏的
b
的類型是with T = std::array<int, 15>&
,即0+1+2+3+4+5 == 15
.閱讀性不強.
C++14
允許較複雜的函數#include<array> template<typename T> void show(T&& t){ t.error(); } constexpr int getSize(int n) { int sum = 0; for(int i = 0 ; i <= n ; i++ ) { sum+=i; } return sum; } int main() { constexpr int len = 5; std::array<int,len> a; std::array<int,getSize(len)> b; show(b); }
c++14
得到一樣的結果,但是C++11
註釋掉shwo
也編不過.提醒
constexpr
用來修飾函數而已,不修飾返回值,也修飾入參.
C++14
加強
允許
class
的成員函數和構造也可以用constexpr
修飾.
c++11
只允許修飾函數和內置類型.
C++14
修飾類成員函數
將一些值設置並提前計算出來,不需要在執行的時候再運算.
#include<array> template<typename T> void show(T&& t){ t.error(); } class T { public: constexpr int getSize(int n) { int sum = 0; for(int i = 0 ; i <= n ; i++ ) { sum+=i; } return sum; } }; int main() { constexpr int len = 5; std::array<int,len> a; std::array<int,T().getSize(len)> b; show(b); }
成員函數的方式獲取到了值.
#include<array> template<typename T> void show(T&& t){ t.error(); } class T { public: constexpr T(int a,int b):a(a),b(b){} constexpr int getSize(int n) { return a * b * n; } private: int a; int b; }; int main() { constexpr int len = 5; std::array<int,len> a; std::array<int,T(2,3).getSize(len)> b; show(b); }
array
的長度是30
. 這裏就是一個constexpr
的對象,複雜類型,而非基礎類型.三個涉及到的元素都是
constexpr
類型.對象
constexpr
即若干個
constexpr
類型的數據的組合.成員函數則是藉助了
constexpr
,即若干個constexpr
作爲入參的函數.#include<array> template<typename T> void show(T&& t){ t.error(); } class T { public: constexpr T(int a,int b):a(a),b(b){} constexpr int getSize(int n) const noexcept { return a * b * n; } private: int a; int b; }; int main() { constexpr int len = 5; constexpr T t{2,3}; std::array<int,len> a; std::array<int,t.getSize(len)> b; show(b); }
對象調用函數的結果作爲模板入參完成.
注意
編譯器做了這些計算工作,所以編譯時間會稍微長一點.
總結
對於變量,能用
constexpr
就儘量使用.
constexpr
可以讓編程更加靈活,在很多場景中發光發熱.和宏定義打交道的地方,應該就可以用到
constexpr
.
constexpr
修飾的函數,如果發生修改,可能會因爲其他人的使用導致編譯失敗.(開閉原則)