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