亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C++17使用折疊表達式實現(xiàn)一個IsAllTrue函數(shù)的過程

 更新時間:2024年09月09日 08:50:10   作者:七昂的技術(shù)之旅  
本文介紹了利用C++17特性實現(xiàn)IsAllTrue函數(shù)的方法,詳細(xì)講解了從基于初始化列表的初級版本到使用折疊表達式和類型萃取的高級優(yōu)化版本,需要的朋友參考下吧

前言

讓我們實現(xiàn)一個 IsAllTrue 函數(shù),支持變長參數(shù),可傳入多個表達式,必須全部計算為true,該函數(shù)才返回true。

本文記錄了逐步實現(xiàn)與優(yōu)化該函數(shù)的思維鏈,用到了以下現(xiàn)代C++新特性知識,適合對C++進階知識有一定了解的人。這樣一種從實際問題來學(xué)習(xí)和運用知識的過程還是挺有趣的,特此整理分享一下。

  • 可變長參數(shù)模板 (C++11)
  • 折疊表達式 (C++17)
  • 條件編譯 if constexpr (C++17)
  • 類型萃取 type traits (C++11)
  • 完美轉(zhuǎn)發(fā)std::forward (C++11)
  • 結(jié)構(gòu)化綁定 std::bind (C++11)

初級版本——基于初始化列表實現(xiàn)

可以使用初始化列表 std::initializer_list 存儲多個bool變量,實現(xiàn)傳入多個bool值的目的,這種方法實際上該函數(shù)只有一個參數(shù),實現(xiàn)如下:

bool IsAllTrue(const std::initializer_list<bool>& conditions) {
    return std::all_of(conditions.begin(), conditions.end(), [](const bool a) {
        return a;
    });
}

使用方法如下:

int a = 1;
bool b = true;
auto c = []() {return true;}
IsAllTrue({a, b, c});

這個方法的實現(xiàn)簡單易用,但是對于代碼有更高追求的人并不滿足于此,以上實現(xiàn)存在如下問題:

  • 傳入?yún)?shù)是一個初始化列表,需要寫大括號{},不夠優(yōu)雅。
  • 調(diào)用函數(shù)前計算了每一個條件表達式,但實際任意一個為false,即可返回,可能存在如下問題:

    不必要的函數(shù)調(diào)用帶來一定計算開銷;

    當(dāng)前后表達式存在依賴關(guān)系時,比如 p && p →a ,如果p是指針且為空, 計算p→a 會導(dǎo)致程序崩潰。

對于不了解這個函數(shù)用法的人而言,使用這個實現(xiàn)是會存在一定風(fēng)險的。所以我們需要想辦法利用 && 實現(xiàn)短路求值,以及對函數(shù)結(jié)果的延遲計算。

進階版本——基于折疊表達式實現(xiàn)

折疊表達式(Fold expressions)

折疊表達式是C++17引入的新特性,可通過二元操作符折疊可變長參數(shù)模板中的參數(shù)包。這個特性的引入是為了簡化C++11可變長參數(shù)模板的使用。

  • 根據(jù)左右方向可分為左折疊右折疊

一元左折疊(Unary right fold)和一元右折疊(Unary left fold)形式如下:

( pack op... )  //一元右折疊,從右往左計算, 等同于(E1 op (... op (EN-1 op EN)))
( ... op pack ) //一元左折疊,從左往右計算, 等同于(((E1 op E2) op ...) op EN)

在大多數(shù)情況下,對于交換律成立的操作符(如 + 和 *),左折疊和右折疊的結(jié)果是相同的。然而,對于非交換的操作符,結(jié)果可能不同,例如減法或除法。

  • 根據(jù)是否有初始值可分為一元二元

二元折疊表達式分為:二元右折疊(Binary right fold)和 二元左折疊(Binary left fold)。

( pack op ... op init )	 //二元右折疊
( init op ... op pack )	 //二元左折疊
  • 使用二元左折疊的例子
template<typename... Args>
void printer(Args&&... args)
{
     ((std::cout<< args << " "), ...)<< "\n";
}

基于一元右折疊的IsAllTrue函數(shù)

基于 &&運算符的一元右折疊(Unary right fold)實現(xiàn)IsAllTrue如下:

template<typename... Args>
bool IsAllTrue(Args... args) { 
	return (std::forward<Args>(args) && ...); 
}
  • 注:折疊表達式的最外層括號是必須的。

但以上實現(xiàn),該模板本質(zhì)上仍只能支持變長的多個bool參數(shù),這會導(dǎo)致先計算出bool值再傳入,仍未實現(xiàn)函數(shù)結(jié)果的延遲計算。

使用type traits 進一步優(yōu)化

如何可以實現(xiàn)延遲計算呢?首先我們可以明確下,傳遞給該函數(shù)的參數(shù)類型,可能是bool值、可以計算出bool值的表達式或可調(diào)用對象、可轉(zhuǎn)換為bool值的指針和數(shù)值。

總體可分為兩類,一類是可轉(zhuǎn)換為bool的表達式,另一類是可計算出bool的可調(diào)用對象。

由于參數(shù)類型(bool、函數(shù)對象、指針等)和類型特征(是否可調(diào)用、是否可以轉(zhuǎn)成bool)均是可以在編譯期確定的。

為了避免在編譯期把模板參數(shù)類型都推斷為bool,可定義 IsTrue 函數(shù)模板定義表達式bool值的計算方式,使模板可以推斷出原表達式自身的類型,從而可以延遲其計算過程。其中用到了編譯期條件if constexpr 和 一種類型萃取是否可調(diào)用 std::is_invocable_v ,這兩個均是C++17引入的特性。

如果具備可調(diào)用的特征,則進行函數(shù)調(diào)用并返回結(jié)果;否則,將其轉(zhuǎn)換為bool值返回。實現(xiàn)如下:

template <typename T>
bool IsTrue(T&& value) {
    if constexpr (std::is_invocable_v<T>) {
        // 如果是可調(diào)用對象,調(diào)用它并返回結(jié)果
        return std::forward<T>(value)();
    } else {
        // 否則,將其轉(zhuǎn)換為bool
        return static_cast<bool>(std::forward<T>(value));
    }
}

基于以上模板改寫 IsAllTure 模板函數(shù) :

template <typename... Args>
bool IsAllTrue(Args&&... args) {
    return (IsTrue(std::forward<Args>(args)) && ...);
}

該實現(xiàn)的本質(zhì)是我們希望在用N個表達式傳入該模板函數(shù)后,模板實例化為形同如下形式,從而可以實現(xiàn)短路機制:

static_cast<bool>(Expr1) && Expr2() && static_cast<bool>(Expr3) && ... && ExprN()

函數(shù)測試

對以上代碼進行如下測試,注釋為輸出結(jié)果,可以看到,能夠滿足我們的需求:

auto lambdaTrue = []() { 
    std::cout<<" lambda true"<<std::endl;
    return true; 
};
auto lambdaFalse = []() { 
    std::cout<<" lambda false"<<std::endl;
    return false; 
};
class Foo  {
public:
    int a;
};
Foo* p = nullptr;
IsAllTrue(true, lambdaTrue);  // 輸出lambda true
IsAllTrue(false, lambdaTrue); // 無輸出,實現(xiàn)了短路機制以及延遲計算
IsAllTrue(p, p->a);  // 正常運行,不會coredump

以上為了方便,均使用定義了無參lambda函數(shù)進行了測試。為了延遲一般含參函數(shù)的計算結(jié)果,能夠方便傳入帶參數(shù)的函數(shù)對象,還可以基于std::bind實現(xiàn)一個用于生成可調(diào)用對象的函數(shù):

template <typename F, typename... Args>
auto make_callable(F&& f, Args&&... args) {
    return std::bind(std::forward<F>(f), std::forward<Args>(args)...);
}

CPP 復(fù)制 全屏

比如:

bool less(int a, int b) {
	return a < b;
}
IsAllTrue(true, make_callable(less, 1, 2));

完整測試代碼:https://compiler-explorer.com/z/fTvq7Y36Y

知識總結(jié)

本文使用了以下C++知識實現(xiàn)了一個高效的IsAllTrue函數(shù),優(yōu)點為它的使用安全且較為高效,缺點在于代碼實現(xiàn)較為復(fù)雜,對C++知識掌握程度要求較高,過多使用也會導(dǎo)致代碼體積膨脹。

  • 條件編譯if constexpr :
    • 這個關(guān)鍵字用于在編譯時判斷是否滿足條件。如果 T 是可調(diào)用對象(例如 lambda 或函數(shù)對象),則調(diào)用它并返回結(jié)果。
    • 如果 T 不是可調(diào)用對象,則將其轉(zhuǎn)換為 bool。
  • 類型萃取std::is_invocable_v
    • 這是一個用于判斷類型 T 是否可調(diào)用的特性。如果 T 是可調(diào)用對象,則 std::is_invocable_v<T> 返回 true
    • 需要包含 <type_traits> 頭文件
  • 完美轉(zhuǎn)發(fā) std::forward
    • std::forward<T>(value) 確保參數(shù)的完美轉(zhuǎn)發(fā),保留其左值或右值性質(zhì)。
  • 可變長參數(shù)模板:支持可變數(shù)量的參數(shù)包,語法用 T ... args表示。
  • 折疊表達式
    • 使用了C++17中的折疊表達式 ,它會對參數(shù)從左到右進行求值。
    • 簡化了可變長參數(shù)模板的使用,提供了一種簡潔而直觀的方式來對參數(shù)包進行展開和操作,從而避免了遞歸或顯式循環(huán)的繁瑣。
  • 結(jié)構(gòu)化綁定 std::bind :可綁定參數(shù)args到一個函數(shù)f,并返回一個可調(diào)用對象。

參考

到此這篇關(guān)于C++17 使用折疊表達式實現(xiàn)一個IsAllTrue函數(shù)的文章就介紹到這了,更多相關(guān)C++ IsAllTrue函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:

相關(guān)文章

  • Windows下Qt打包自動尋找依賴的DLL

    Windows下Qt打包自動尋找依賴的DLL

    本文介紹了兩種在Windows下使用Qt打包應(yīng)用程序并自動尋找依賴DLL的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-12-12
  • C++11標(biāo)準(zhǔn)庫 互斥鎖 <mutex> 詳解

    C++11標(biāo)準(zhǔn)庫 互斥鎖 <mutex> 詳解

    這篇文章主要介紹了C++11標(biāo)準(zhǔn)庫互斥鎖 <mutex> 的相關(guān)知識,使用call_once()的時候,需要一個once_flag作為call_once()的傳入?yún)?shù),本文給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧
    2024-07-07
  • C語言實現(xiàn)合并字符串

    C語言實現(xiàn)合并字符串

    今天小編就為大家分享一篇C語言實現(xiàn)合并字符串,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • C++實現(xiàn)Dijkstra算法的示例代碼

    C++實現(xiàn)Dijkstra算法的示例代碼

    迪杰斯特拉算法(Dijkstra)是由荷蘭計算機科學(xué)家狄克斯特拉于1959年提出的,因此又叫狄克斯特拉算法。是從一個頂點到其余各頂點的最短路徑算法。本文將用C++實現(xiàn)Dijkstra算法,需要的可以參考一下
    2022-07-07
  • C語言實現(xiàn)數(shù)據(jù)結(jié)構(gòu)和雙向鏈表操作

    C語言實現(xiàn)數(shù)據(jù)結(jié)構(gòu)和雙向鏈表操作

    這篇文章主要介紹了C語言實現(xiàn)數(shù)據(jù)結(jié)構(gòu)雙向鏈表操作,需要的朋友可以參考下
    2017-03-03
  • C++超詳細(xì)講解模板的使用

    C++超詳細(xì)講解模板的使用

    這篇文章主要介紹了C++中模板(Template)的詳解及其作用介紹,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • C語言實現(xiàn)簡易五子棋小游戲

    C語言實現(xiàn)簡易五子棋小游戲

    這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)簡單五子棋小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-05-05
  • linux C 打印錯誤信息和標(biāo)準(zhǔn)輸入輸出詳細(xì)介紹

    linux C 打印錯誤信息和標(biāo)準(zhǔn)輸入輸出詳細(xì)介紹

    這篇文章主要介紹了linux C 打印錯誤信息和標(biāo)準(zhǔn)輸入輸出詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下
    2016-12-12
  • 用C語言簡單實現(xiàn)掃雷小游戲

    用C語言簡單實現(xiàn)掃雷小游戲

    這篇文章主要為大家詳細(xì)介紹了用C語言簡單實現(xiàn)掃雷小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • 淺談C++11的std::function源碼解析

    淺談C++11的std::function源碼解析

    類模版std::function是一種通用的多態(tài)函數(shù)包裝器std::function的實例可以對任何可以調(diào)用的目標(biāo)實體進行存儲、復(fù)制、和調(diào)用操作,本文詳細(xì)的介紹一下,感興趣的可以了解一下
    2021-06-06

最新評論