C++中constexpr與函數(shù)參數(shù)轉(zhuǎn)發(fā)的操作方法
序
本文和大家探討下關于constexpr的函數(shù)中參數(shù)的現(xiàn)象,以及如果參數(shù)是constexpr如何做轉(zhuǎn)發(fā)
關于constexpr函數(shù)
constexpr是c++11引入的關鍵字,c++11的constexpr的函數(shù)中只是支持單句代碼,c++14限制放寬,可以在里邊寫循環(huán)及邏輯判斷等語句。
constexpr形容函數(shù)表示該函數(shù)被編譯期計算或者調(diào)用。但是只能是可能被編譯期計算,舉例來說:
constexpr int square(int num) { return num * num; }
假設這里有一個計算平方的函數(shù)是constexpr形容,那么我如果這樣調(diào)用:
int main() { int val = square(12); }
我們可以看下編譯后的匯編:
main: push rbp mov rbp, rsp mov DWORD PTR [rbp-4], 144 // 這里 mov eax, 0 pop rbp ret
可以看到main函數(shù)里在運行時根本沒有去調(diào)用square
函數(shù),而是在編譯期直接將square
函數(shù)計算得出144并賦值。也就是說傳遞參數(shù)是字面量(或者constexpr變量)可以被認定是編譯期調(diào)用。
那么我們?nèi)绻麚Q一種方式調(diào)用呢?
int main() { int p = 12; int val = square(p); }
通過參數(shù)傳遞進來,再來看下匯編:
square(int): push rbp mov rbp, rsp mov DWORD PTR [rbp-4], edi mov eax, DWORD PTR [rbp-4] imul eax, eax pop rbp ret main: push rbp mov rbp, rsp sub rsp, 16 mov DWORD PTR [rbp-4], 12 mov eax, DWORD PTR [rbp-4] mov edi, eax call square(int) mov DWORD PTR [rbp-8], eax mov eax, 0 leave ret
略顯復雜,不需要關注很多匯編代碼,我們只需要知道運行時確實會去執(zhí)行square函數(shù)。
constexpr函數(shù)小結
那也就是說constexpr函數(shù)并不是完全是編譯期執(zhí)行,編譯器其實和你傳遞的參數(shù)或者函數(shù)內(nèi)部的一些邏輯來判斷。
constexpr參數(shù)傳遞
這里假設有一個這樣的例子:
// ... struct AddSum { void add(int val) { constexpr auto sq = square(val); sum += sq; } int sum = 0; }; int main() { constexpr int p = 12; AddSum a; a.add(p); return 0; }
需要把一些編譯期的數(shù)字的平方加起來,在add函數(shù)中使用constexpr
來接收square的返回值,因為這樣可以使得square是編譯期執(zhí)行的,不過可惜的是這里不能通過編譯,因為square不能確定val是不是constexpr
。但是我們明明傳遞的就是constexpr
的變量。那么問題來了,如何在傳參數(shù)的時候能夠?qū)?code>constexpr的屬性進行傳遞呢?
C++并不支持在形參使用constexpr限制:
// error: Function parameter cannot be constexpr void add(constexpr int val) { // ... }
且使用完美轉(zhuǎn)發(fā)也不能將constexpr進行傳遞。
template<typename T> void add(T&& val) { constexpr auto sq = square(val); // error }
使用非類型模板參數(shù)
既然用到了模板,那么我們完全可以將val作為非類型的模板參數(shù)進行傳遞:
template<int val> void add() { constexpr auto sq = square(val); sum += sq; }
如果這里就結束的話,那確實不值得討論了,非類型模板參數(shù)的問題是只能傳遞一些基本類型,我們自定的類constexpr對象則不能傳遞。
值內(nèi)嵌的類型
其實我們可以借助一個helper類,將要傳遞的值封裝在這里類里,然后需要的時候取出來。如下:
struct Helper { static constexpr int value() { return 12; } }; struct AddSum { template<typename H> void add(H) { constexpr auto sq = square(H::value()); sum += sq; } int sum = 0; }; int main() { AddSum a; a.add(Helper{}); return 0; }
可以看到我們Helper
中value用來封裝了要傳遞的int值,然后將Helper的對象傳遞給add,進一步可以獲取到value。
這里不能通用,因為我們需要在helper里寫死這個值,又沒辦法將值傳遞給helper,感覺又繞回來了。哈哈,這里我們使用宏來定義一個通用的模式:
#define CONSTEXPR_HELPER(...) \ struct Helper { \ static constexpr decltype(auto) value() { \ return __VA_ARGS__; \ } \ }; int main() { AddSum a; using H = CONSTEXPR_HELPER(12); a.add(H{}); return 0; }
這種情況下就可以使用任意類型的的constexpr屬性進行傳遞了。同時也可以將值在調(diào)用時傳遞而不是寫死。
constexpr的lambda表達式
C++17出現(xiàn)了constexpr形式的lambda表達式,我們可以借助它來實現(xiàn)constexpr的傳遞
struct AddSum { template<typename H> void add(H h) { constexpr auto sq = square(h()); sum += sq; } int sum = 0; }; int main() { AddSum a; a.add([](){ return 12; }); return 0; }
這里我們使用constexpr的lambda對象傳遞給add
函數(shù),同時傳遞過來的lambda表達式仍然具有l(wèi)ambda屬性,然后調(diào)用將值獲取到。
這樣也就是在C++17版本不需要使用宏來定義內(nèi)嵌值的類型。
總結
本篇文章就是和大家探討下constexpr的參數(shù)傳遞的問題,可以使用非類型模板參數(shù),宏定義,lambda表達式做到。
感謝大家,點個贊吧~
ref
https://mpark.github.io/programming/2017/05/26/constexpr-function-parameters/
到此這篇關于C++中constexpr與函數(shù)參數(shù)轉(zhuǎn)發(fā)的文章就介紹到這了,更多相關constexpr函數(shù)參數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C++實現(xiàn)LeetCode(151.翻轉(zhuǎn)字符串中的單詞)
這篇文章主要介紹了C++實現(xiàn)LeetCode(151.翻轉(zhuǎn)字符串中的單詞),本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下2021-07-07C++內(nèi)存四區(qū)之代碼區(qū)、全局區(qū)、棧區(qū)和堆區(qū)
C++編譯器會把代碼直接分為四個小區(qū),弄懂這四小區(qū)對我們理解內(nèi)存有所幫助,所以下面這篇文章主要給大家介紹了關于C++內(nèi)存四區(qū)之代碼區(qū)、全局區(qū)、棧區(qū)和堆區(qū)的相關資料,需要的朋友可以參考下2021-07-07C語言的可變參數(shù)函數(shù)實現(xiàn)詳解
某些情況下我們希望函數(shù)的參數(shù)個數(shù)可以根據(jù)需要確定,因此c語言引入可變參數(shù)函數(shù)。典型的可變參數(shù)函數(shù)的例子有printf()、scanf()等,下面我就開始講解2021-08-08