C++ 11 中引入的所有特性中, 最讓人困惑的也許是 constexpr
. 我也曾經被它困惑了一段時間, 儘管我在《C++ 學習筆記》中講述地比較詳細, 不過我早已解決了這個困惑. 如今閱讀《Effective Modern C++》的過程中, 還是決定專門為 constexpr
寫一篇文章, 幫助大家更加深入地理解 constexpr
. 這篇文章旨在幫你深入理解 constexpr
, 如果你一點都不了解 constexpr
, 我想你應該去看一下我那篇《C++ 學習筆記》, 了解一下先
在開始細談之前, 我首先來總結一下 constexpr
: 針對變數標識的 constexpr
表示該變數必定是編碼期就已知的變數, 也就是所謂的字面值常數表達式; 而針對函式標識的 constexpr
表明該函式有編碼期處理的能力, 但是函式的運作不一定就非要在編碼期, 也可以在運作期
這個總結透露出了一個重要的信息, 就是 constexpr
在變數上和在函式上的行為並不一致. 對於變數來說, 如果它被 constexpr
標識, 那麼它必定是編碼期已知的, 那麼它可以被用於標識陣列大小, 用在樣板引數上; 但是對於函式來說, 即使它被 constexpr
標識, 它也不是非要運作在編碼期, 而是可以在運作期執行. 因此, 我們要講語境分成兩個 :
- 編碼期語境
- 運作期語境
被 constexpr
標識的函式, 如果存在某條陳述式在編碼期無法運作 (比如其呼叫的函式非 constexpr
函式或者某個變數在編碼期未知), 那麼整個函式會被推遲到運作期才運作; 否則, 函式的運作結果會在編碼期就產生. 相比較於 inline
, 編碼器在處理 constexpr
函式的時候, 會盡力使得其可以在編碼期就產生結果; 但是對於 inline
來說, 編碼器並不盡力, 你的 inline
請求可能會被編碼器忽略
至於某個被 constexpr
標識的函式是否產生了編碼器就可以得到的結果, 可以將其的回傳值放入到樣板引數或者陣列宣告中. 如果沒有產生編碼錯誤, 那麼結果就是在編碼期就產生; 否則, 函式需要等到運作期才會執行
如果沒有 constexpr
, 如果程式的某個地方要求編碼期語境的運作結果, 那麼此時我們還可能需要借助 template
來撰寫一個超函式
在 C++ 11 中, 由于 constexpr
的严格限制, 大部分被 constexpr
標識的函式幾乎可以在編碼期處理完成. 但是在 C++ 14 之後, constexpr
函式的限制被大大地放開, 大部分函式都可以被 constexpr
標識. 而在 C++ 20 之後, constexpr
的限制又被放開, 幾乎所有函式都可以被 constexpr
標識. 我們已經在《Paper Guide》欄目中介紹過 C++ 14 中是如何緩和 constexpr
函式的限制的. 在 C++ 20, 幾乎任何函式都可以被 constexpr
標識, 我們也將在《Paper Guide》欄目中介紹 C++ 20 的 constexpr
C++ 的發展已經越來越致力於 everything constexpr
. 其實個人覺得必要不是特別大, 因為 everything constexpr
可以作為一個語言的特點來宣傳, 而 C++ 連 Module、Coroutine、Network 和 Reflection 這些該有的還處於殘缺的狀態
自創文章, 原著 : Jonny, 如若需要轉發, 在已經授權的情況下請註明出處 :《【C++】細談 constexpr》https://jonny.vip/2020/09/05/%e3%80%90cplusplus%e3%80%91%e7%b4%b0%e8%ab%87-constexpr/
Leave a Reply