C++中的constexpr的意义与用法
以下内容转载medium, 字体为繁体, 不喜欢勿入, 无奈许多博客的介绍都写的太差, 这位台湾小哥是看过写的最清晰最棒的, 由简入深 !
内容转载https://medium.com/@tjsw/%E6%BD%AE-c-constexpr-constructor-constexpr-operator-overloading-3a11062900ff
Part1
近代的 C++ 中為我們傳統熟悉的語句和修飾子多了非常多的元素,今天就來聊聊 C++11 開始引入的 constexpr 修飾子的用法吧。
constexpr
是 C++11 對於我們已經熟到透的 const 修飾子的一個加強。 const 大家都知道是代表英文中 constant,常數的意思。代表的是被修飾的變數數值編譯期 (compile-time) 已定,也無法再通過語法修改,任何對於標示為常數的變數的嘗試修改都會造成編譯器報錯。
constexpr擴展了原本對於const的限制,並且明確地給了編譯器更多在編譯時期就可以做的計算空間,讓執行期減少更多不必要的計算。以往需要藉由面目全非的 template meta programming 才能完成的編譯期計算現在可以我們最平常的函式語言就能夠完成。
Part2
constexpr 的用法中我們提過一個 C++ 函式只要滿足一些簡單的限制,現代 C++ 編譯器就可以幫你在編譯期算出函式的結果。而我們一直沒有提到的類別的 constructor 以及類別的 member function 成員函式甚至是 operator overloading 運算子重載,他也是一個函式啊!是不是也能加上 constexpr 修飾呢?
答案當然是可以,不然這篇就不用寫了。
那麼具體來說 constexpr 加在類別的成員函式們可以幹嘛?就是希望我們開發 者自定義的類別也可以宣告成 constexpr 變數,達到編譯期的運算效果。
cube()還是一個標上constexpr的函式,代表了裡面的運算元 ©,以及運算 () 都要是編譯時期可知的操作,也就是c * c * c必須是一個 constant expression
c1 也掛上 constexpr,因此他的初始化操作也必須是一個 constexpr function。結上所述,我們必須對 CClass 的 constructor,以及 operator() 加上 constexpr 的修飾。
一個 constructor 畢竟代表了整個類別的性質,掛上 constexpr 的 constructor 就代表使用者自定義的類別是一個字面型別 (literal type)。
因此整個類別被拿用初始化 constexpr 變數時 (例如 main() 的 c1) ,必須確保除了 constexpr constructor 裡面沒有奇怪的操作,而且所有的成員變數都要被初始化列表 (member initialization list) 以編譯時期可知的值初始化。(或是成員宣告直接賦值也行)
完整的 CClass 定義應該是這樣的:
CClass的 constructor 完全沒有操作,也初始化了所有,也是唯一的成員變數n_,因此自然就符合了constexpr的限制。(可以試試看把 n_ 寫在 constructor 函式體裡面賦值,就會吃 compile error 了)
operator*() 就是個成員函式,做了一個 constexpr 物件回來,也很乖巧。所以我們再度利用組語編譯,也能發現編譯器的確把 c2_6, c3_6 在編譯時期就算出來了。
.section __TEXT,__const
.p2align 2 ## @_ZZ4mainE2c1
__ZZ4mainE2c1:
.long 4 ## 0x4.p2align 2 ## @ZZ4mainE4c2_6
ZZ4mainE4c2_6:
.long 64 ## 0x40.p2align 2 ## @ZZ4mainE4c3_6
ZZ4mainE4c3_6:
.long 729 ## 0x2d9
也可以不要編譯期算
constexpr CClass c2_6 = cube(c1);
constexpr CClass c3_6 = cube(CClass(sq(3)));
CClass c88(88);static_assert(c2_6.n == 64, “!!!”);
static_assert(c3_6.n == 729, “!!!”);printf("%d %d %d\n", c2_6.n, c3_6.n, c88.n);
就像 constexpr function 一樣,根據我們在什麼時候使用,就可以編譯期算,或是執行期才算。比如上面這個 c88,他就不會是一個在 TEXT 段的常數。而是執行期呼叫 printf() 的時候才把 n 從 register 裡面拿出來壓進 stack 裡呼叫 printf()。
今天的內容很簡單,就是再把 constexpr 的適用範圍再擴展
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
