C++ Boost Phoenix庫示例分析使用
一、說明
在函數(shù)式編程模型中,函數(shù)是對(duì)象,與其他對(duì)象一樣,可以作為參數(shù)傳遞給函數(shù)或存儲(chǔ)在容器中。有許多支持函數(shù)式編程模型的 Boost 庫。
- Boost.Phoenix 是這些庫中最廣泛、也是最重要的庫。它取代了庫 Boost.Lambda,它被簡(jiǎn)要介紹,但只是為了完整性。
- Boost.Function 提供了一個(gè)類,可以輕松定義函數(shù)指針,而無需使用源自 C 編程語言的語法。
- Boost.Bind 是一個(gè)適配器,即使實(shí)際簽名與預(yù)期簽名不同,它也允許您將函數(shù)作為參數(shù)傳遞給其他函數(shù)。
- Boost.Ref 可用于傳遞對(duì)對(duì)象的引用,即使函數(shù)通過副本傳遞參數(shù)。
- Boost.Lambda 可以稱為 Boost.Phoenix 的前身。它是一個(gè)相當(dāng)古老的庫,并且在將 C++11 添加到編程語言之前很多年就允許使用 lambda 函數(shù)。
二、預(yù)先知道Boost.Phoenix
Boost.Phoenix 是函數(shù)式編程最重要的 Boost 庫。雖然 Boost.Bind 或 Boost.Lambda 等庫為函數(shù)式編程提供了一些支持,但 Boost.Phoenix 包含這些庫的功能并超越了它們。
在函數(shù)式編程中,函數(shù)是對(duì)象,可以像對(duì)象一樣處理。使用 Boost.Phoenix,一個(gè)函數(shù)可以返回另一個(gè)函數(shù)作為結(jié)果。也可以將一個(gè)函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù)。因?yàn)楹瘮?shù)是對(duì)象,所以可以區(qū)分實(shí)例化和執(zhí)行。訪問一個(gè)函數(shù)不等于執(zhí)行它。
Boost.Phoenix 支持使用函數(shù)對(duì)象進(jìn)行函數(shù)式編程:函數(shù)是基于類的對(duì)象,這些類重載了運(yùn)算符 operator()。這樣,函數(shù)對(duì)象的行為就像 C++ 中的其他對(duì)象一樣。例如,它們可以被復(fù)制并存儲(chǔ)在容器中。但是,它們的行為也類似于函數(shù),因?yàn)樗鼈兛梢员徽{(diào)用。
函數(shù)式編程在 C++ 中并不新鮮。您可以將一個(gè)函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù),而無需使用 Boost.Phoenix。
三、示例和代碼
示例 39.1。謂詞作為全局函數(shù)、lambda 函數(shù)和 Phoenix 函數(shù)
#include <boost/phoenix/phoenix.hpp> #include <vector> #include <algorithm> #include <iostream> bool is_odd(int i) { return i % 2 == 1; } int main() { std::vector<int> v{1, 2, 3, 4, 5}; std::cout << std::count_if(v.begin(), v.end(), is_odd) << '\n'; auto lambda = [](int i){ return i % 2 == 1; }; std::cout << std::count_if(v.begin(), v.end(), lambda) << '\n'; using namespace boost::phoenix::placeholders; auto phoenix = arg1 % 2 == 1; std::cout << std::count_if(v.begin(), v.end(), phoenix) << '\n'; }
示例 39.1 使用算法 std::count_if() 來計(jì)算向量 v 中的奇數(shù)。std::count_if() 被調(diào)用 3 次,一次使用謂詞作為獨(dú)立函數(shù),一次使用 lambda 函數(shù),一次使用鳳凰功能。
Phoenix 函數(shù)與獨(dú)立函數(shù)和 lambda 函數(shù)不同,因?yàn)樗鼪]有框架。雖然其他兩個(gè)函數(shù)有一個(gè)帶有簽名的函數(shù)頭,但 Phoenix 函數(shù)似乎只包含一個(gè)函數(shù)體。
Phoenix 函數(shù)的關(guān)鍵組件是 boost::phoenix::placeholders::arg1。 arg1 是函數(shù)對(duì)象的全局實(shí)例。您可以像 std::cout 一樣使用它:一旦包含相應(yīng)的頭文件,這些對(duì)象就會(huì)存在。
arg1 用于定義一元函數(shù)。表達(dá)式 arg1 % 2 == 1 創(chuàng)建一個(gè)需要一個(gè)參數(shù)的新函數(shù)。該函數(shù)不會(huì)立即執(zhí)行,而是存儲(chǔ)在 Phoenix 中。 phoenix 被傳遞給 std::count_if() ,它為 v 中的每個(gè)數(shù)字調(diào)用謂詞。
arg1 是調(diào)用 Phoenix 函數(shù)時(shí)傳遞的值的占位符。由于此處僅使用了 arg1,因此創(chuàng)建了一個(gè)一元函數(shù)。 Boost.Phoenix 提供了額外的占位符,例如 boost::phoenix::placeholders::arg2 和 boost::phoenix::placeholders::arg3。 Phoenix 函數(shù)總是期望與具有最大數(shù)量的占位符一樣多的參數(shù)。
示例 39.1 將 3 寫入標(biāo)準(zhǔn)輸出 3 次。
示例 39.2。 Phoenix 函數(shù)與 lambda 函數(shù)
#include <boost/phoenix/phoenix.hpp> #include <vector> #include <algorithm> #include <iostream> int main() { std::vector<int> v{1, 2, 3, 4, 5}; auto lambda = [](int i){ return i % 2 == 1; }; std::cout << std::count_if(v.begin(), v.end(), lambda) << '\n'; std::vector<long> v2; v2.insert(v2.begin(), v.begin(), v.end()); using namespace boost::phoenix::placeholders; auto phoenix = arg1 % 2 == 1; std::cout << std::count_if(v.begin(), v.end(), phoenix) << '\n'; std::cout << std::count_if(v2.begin(), v2.end(), phoenix) << '\n'; }
例 39.2 強(qiáng)調(diào)了 Phoenix 和 lambda 函數(shù)之間的一個(gè)關(guān)鍵區(qū)別。除了不需要帶有參數(shù)列表的函數(shù)頭之外,Phoenix 函數(shù)參數(shù)沒有類型。 lambda 函數(shù) lambda 需要一個(gè) int 類型的參數(shù)。 Phoenix 函數(shù) phoenix 將接受模運(yùn)算符可以處理的任何類型。
將 Phoenix 函數(shù)視為函數(shù)模板。像函數(shù)模板一樣,Phoenix 函數(shù)可以接受任何類型。這使得在示例 39.2 中可以使用 phoenix 作為容器 v 和 v2 的謂詞,即使它們存儲(chǔ)不同類型的數(shù)字。如果您嘗試將謂詞 lambda 與 v2 一起使用,則會(huì)出現(xiàn)編譯器錯(cuò)誤。
示例 39.3。 Phoenix 用作延遲 C++ 代碼
#include <boost/phoenix/phoenix.hpp> #include <vector> #include <algorithm> #include <iostream> int main() { std::vector<int> v{1, 2, 3, 4, 5}; using namespace boost::phoenix::placeholders; auto phoenix = arg1 > 2 && arg1 % 2 == 1; std::cout << std::count_if(v.begin(), v.end(), phoenix) << '\n'; }
示例 39.3 使用 Phoenix 函數(shù)作為謂詞,使用 std::count_if() 計(jì)算大于 2 的奇數(shù)。Phoenix 函數(shù)訪問 arg1 兩次:一次測(cè)試占位符是否大于 2,一次測(cè)試它是否為奇數(shù).條件與 && 相關(guān)聯(lián)。
您可以將 Phoenix 函數(shù)視為不會(huì)立即執(zhí)行的 C++ 代碼。示例 39.3 中的 Phoenix 函數(shù)看起來像一個(gè)使用多個(gè)邏輯和算術(shù)運(yùn)算符的條件。但是,條件不會(huì)立即執(zhí)行。它僅在從 std::count_if() 中訪問時(shí)執(zhí)行。 std::count_if() 中的訪問是正常的函數(shù)調(diào)用。
示例 39.3 將 2 寫入標(biāo)準(zhǔn)輸出。
示例 39.4。顯式 Phoenix 類型
#include <boost/phoenix/phoenix.hpp> #include <vector> #include <algorithm> #include <iostream> int main() { std::vector<int> v{1, 2, 3, 4, 5}; using namespace boost::phoenix; using namespace boost::phoenix::placeholders; auto phoenix = arg1 > val(2) && arg1 % val(2) == val(1); std::cout << std::count_if(v.begin(), v.end(), phoenix) << '\n'; }
例 39.4 對(duì) Phoenix 函數(shù)中的所有操作數(shù)使用顯式類型。嚴(yán)格來說,你看不到類型,只有輔助函數(shù) boost::phoenix::val()。此函數(shù)返回使用傳遞給 boost::phoenix::val() 的值初始化的函數(shù)對(duì)象。函數(shù)對(duì)象的實(shí)際類型無關(guān)緊要。重要的是 Boost.Phoenix 為不同類型重載了運(yùn)算符,如 >、&&、% 和 ==。因此,不會(huì)立即檢查條件。相反,函數(shù)對(duì)象被組合以創(chuàng)建更強(qiáng)大的函數(shù)對(duì)象。根據(jù)操作數(shù),它們可能會(huì)自動(dòng)用作函數(shù)對(duì)象。否則,您可以調(diào)用 val() 等輔助函數(shù)。
示例 39.5。 boost::phoenix::placeholders::arg1 和 boost::phoenix::val()
#include <boost/phoenix/phoenix.hpp> #include <iostream> int main() { using namespace boost::phoenix::placeholders; std::cout << arg1(1, 2, 3, 4, 5) << '\n'; auto v = boost::phoenix::val(2); std::cout << v() << '\n'; }
示例 39.5 說明了 arg1 和 val() 如何工作。 arg1 是函數(shù)對(duì)象的實(shí)例。它可以直接使用,也可以像函數(shù)一樣調(diào)用。您可以傳遞任意數(shù)量的參數(shù)——arg1 返回第一個(gè)參數(shù)。
val() 是一個(gè)用于創(chuàng)建函數(shù)對(duì)象實(shí)例的函數(shù)。函數(shù)對(duì)象使用作為參數(shù)傳遞的值進(jìn)行初始化。如果實(shí)例像函數(shù)一樣被訪問,則返回該值。
示例 39.5 將 1 和 2 寫入標(biāo)準(zhǔn)輸出。
示例 39.6。創(chuàng)建自己的 Phoenix 函數(shù)
#include <boost/phoenix/phoenix.hpp> #include <vector> #include <algorithm> #include <iostream> struct is_odd_impl { typedef bool result_type; template <typename T> bool operator()(T t) const { return t % 2 == 1; } }; boost::phoenix::function<is_odd_impl> is_odd; int main() { std::vector<int> v{1, 2, 3, 4, 5}; using namespace boost::phoenix::placeholders; std::cout << std::count_if(v.begin(), v.end(), is_odd(arg1)) << '\n'; }
示例 39.6 解釋了如何創(chuàng)建自己的 Phoenix 函數(shù)。您將函數(shù)對(duì)象傳遞給模板 boost::phoenix::function。該示例傳遞了 is_odd_impl 類。此類重載運(yùn)算符 operator():當(dāng)傳入奇數(shù)時(shí),運(yùn)算符返回 true。否則,運(yùn)算符返回 false。
請(qǐng)注意,您必須定義類型result_type。 Boost.Phoenix 使用它來檢測(cè)運(yùn)算符 operator() 的返回值的類型。
is_odd() 是一個(gè)可以像 val() 一樣使用的函數(shù)。兩個(gè)函數(shù)都返回一個(gè)函數(shù)對(duì)象。調(diào)用時(shí),參數(shù)將轉(zhuǎn)發(fā)給運(yùn)算符 operator()。對(duì)于示例 39.6,這意味著 std::count_if() 仍然計(jì)算奇數(shù)。
示例 39.7。將獨(dú)立功能轉(zhuǎn)換為 Phoenix 功能
#include <boost/phoenix/phoenix.hpp> #include <vector> #include <algorithm> #include <iostream> bool is_odd_function(int i) { return i % 2 == 1; } BOOST_PHOENIX_ADAPT_FUNCTION(bool, is_odd, is_odd_function, 1) int main() { std::vector<int> v{1, 2, 3, 4, 5}; using namespace boost::phoenix::placeholders; std::cout << std::count_if(v.begin(), v.end(), is_odd(arg1)) << '\n'; }
如果要將獨(dú)立函數(shù)轉(zhuǎn)換為 Phoenix 函數(shù),可以按照示例 39.7 進(jìn)行操作。您不必像前面的示例中那樣定義函數(shù)對(duì)象。
您可以使用宏 BOOST_PHOENIX_ADAPT_FUNCTION 將獨(dú)立函數(shù)轉(zhuǎn)換為 Phoenix 函數(shù)。將返回值的類型、要定義的 Phoenix 函數(shù)的名稱、獨(dú)立函數(shù)的名稱以及參數(shù)個(gè)數(shù)傳遞給宏。
示例 39.8。 Phoenix 使用 boost::phoenix::bind() 函數(shù)
#include <boost/phoenix/phoenix.hpp> #include <vector> #include <algorithm> #include <iostream> bool is_odd(int i) { return i % 2 == 1; } int main() { std::vector<int> v{1, 2, 3, 4, 5}; using namespace boost::phoenix; using namespace boost::phoenix::placeholders; std::cout << std::count_if(v.begin(), v.end(), bind(is_odd, arg1)) << '\n'; }
要將獨(dú)立函數(shù)用作 Phoenix 函數(shù),您還可以使用 boost::phoenix::bind(),如示例 39.8 中所示。 boost::phoenix::bind() 的工作方式類似于 std::bind()。獨(dú)立函數(shù)的名稱作為第一個(gè)參數(shù)傳遞。所有進(jìn)一步的參數(shù)都被轉(zhuǎn)發(fā)到獨(dú)立功能。
小費(fèi)
避免使用 boost::phoenix::bind()。創(chuàng)建您自己的 Phoenix 函數(shù)。這會(huì)導(dǎo)致代碼更具可讀性。尤其是對(duì)于復(fù)雜的表達(dá)式,處理 boost::phoenix::bind() 的額外細(xì)節(jié)是沒有幫助的。
示例 39.9。任意復(fù)雜的 Phoenix 函數(shù)
#include <boost/phoenix/phoenix.hpp> #include <vector> #include <algorithm> #include <iostream> int main() { std::vector<int> v{1, 2, 3, 4, 5}; using namespace boost::phoenix; using namespace boost::phoenix::placeholders; int count = 0; std::for_each(v.begin(), v.end(), if_(arg1 > 2 && arg1 % 2 == 1) [ ++ref(count) ]); std::cout << count << '\n'; }
Boost.Phoenix 提供了一些模擬 C++ 關(guān)鍵字的函數(shù)對(duì)象。例如,您可以使用函數(shù) boost::phoenix::if_()(參見示例 39.9)創(chuàng)建一個(gè)函數(shù)對(duì)象,該對(duì)象的行為類似于 if 并測(cè)試條件。如果條件為真,則使用 operator[] 傳遞給函數(shù)對(duì)象的代碼將被執(zhí)行。當(dāng)然,該代碼也必須基于函數(shù)對(duì)象。這樣,您可以創(chuàng)建復(fù)雜的 Phoenix 函數(shù)。
示例 39.9 對(duì)每個(gè)大于 2 的奇數(shù)進(jìn)行增量計(jì)數(shù)。要對(duì) count 使用增量運(yùn)算符,請(qǐng)使用 boost::phoenix::ref() 將 count 包裝在一個(gè)函數(shù)對(duì)象中。與 boost::phoenix::val() 相比,沒有值被復(fù)制到函數(shù)對(duì)象中。 boost::phoenix::ref() 返回的函數(shù)對(duì)象存儲(chǔ)了一個(gè)引用——這里是對(duì) count 的引用。
小提示
不要使用 Boost.Phoenix 創(chuàng)建復(fù)雜的函數(shù)。最好使用 C++11 中的 lambda 函數(shù)。雖然 Boost.Phoenix 接近 C++ 語法,但使用 if_ 等關(guān)鍵字或方括號(hào)之間的代碼塊并不一定會(huì)提高可讀性。
到此這篇關(guān)于C++ Boost Phoenix庫示例分析使用的文章就介紹到這了,更多相關(guān)C++ Boost Phoenix庫內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++標(biāo)準(zhǔn)模版庫(STL)之vector容器詳解
vector的功能和水桶一樣,就是用來裝東西的,并且vector還提供了迭代器來很方便的訪問這些數(shù)據(jù),下面就讓我們一起看下如何使用C++的vector吧2023-03-03C++實(shí)戰(zhàn)之二進(jìn)制數(shù)據(jù)處理與封裝
在電腦上一切數(shù)據(jù)都是通過二進(jìn)制(0或1)進(jìn)行存儲(chǔ)的,通過多位二進(jìn)制數(shù)據(jù)可以進(jìn)而表示整形、浮點(diǎn)型、字符、字符串等各種基礎(chǔ)類型數(shù)據(jù)或者一些更復(fù)雜的數(shù)據(jù)格式。本文將為大家詳細(xì)講講二進(jìn)制數(shù)據(jù)處理與封裝,需要的可以參考一下2022-08-08C語言實(shí)現(xiàn)為無聲avi視頻添加wave音樂
這篇文章主要為大家詳細(xì)介紹了C語言如何實(shí)現(xiàn)為無聲avi視頻添加wave音樂,文中的示例代碼講解詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴可以了解一下2023-11-11C語言實(shí)現(xiàn)簡(jiǎn)單五子棋小游戲
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)簡(jiǎn)單五子棋小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-08-08