C++ Boost Fusion創(chuàng)建異構(gòu)容器詳解
一、說(shuō)明
標(biāo)準(zhǔn)庫(kù)提供了許多容器,它們有一個(gè)共同點(diǎn):它們是同類(lèi)的。也就是說(shuō),標(biāo)準(zhǔn)庫(kù)中的容器只能存儲(chǔ)一種類(lèi)型的元素。 std::vector<int> 類(lèi)型的向量只能存儲(chǔ) int 值,而 std::vector<std::string> 類(lèi)型的向量只能存儲(chǔ)字符串。
Boost.Fusion 使創(chuàng)建異構(gòu)容器成為可能。例如,您可以創(chuàng)建一個(gè)向量,其第一個(gè)元素是 int,第二個(gè)元素是字符串。此外,Boost.Fusion 提供了處理異構(gòu)容器的算法。您可以將 Boost.Fusion 視為異構(gòu)容器的標(biāo)準(zhǔn)庫(kù)。
嚴(yán)格來(lái)說(shuō),從C++11開(kāi)始,標(biāo)準(zhǔn)庫(kù)就提供了一個(gè)異構(gòu)容器,std::tuple。您可以對(duì)存儲(chǔ)在元組中的值使用不同的類(lèi)型。 Boost.Fusion 中的 boost:fusion::tuple 是類(lèi)似的類(lèi)型。雖然標(biāo)準(zhǔn)庫(kù)沒(méi)有提供更多,但元組只是 Boost.Fusion 的起點(diǎn)。
二、示例和代碼
示例 50.1。處理融合元組
#include <boost/fusion/tuple.hpp> #include <string> #include <iostream> using namespace boost::fusion; int main() { typedef tuple<int, std::string, bool, double> tuple_type; tuple_type t{10, "Boost", true, 3.14}; std::cout << get<0>(t) << '\n'; std::cout << get<1>(t) << '\n'; std::cout << std::boolalpha << get<2>(t) << '\n'; std::cout << get<3>(t) << '\n'; }
示例 50.1 定義了一個(gè)由 int、std::string、bool 和 double 組成的元組。該元組基于 boost:fusion::tuple。在示例 50.1 中,元組隨后被實(shí)例化、初始化,并使用 boost::fusion::get() 檢索各種元素并寫(xiě)入標(biāo)準(zhǔn)輸出。函數(shù) boost::fusion::get() 類(lèi)似于 std::get(),它訪(fǎng)問(wèn) std::tuple 中的元素。
融合元組與標(biāo)準(zhǔn)庫(kù)中的元組沒(méi)有區(qū)別。因此,Boost.Fusion 提供函數(shù) boost::fusion::make_tuple() 就不足為奇了,它的工作方式類(lèi)似于 std::make_tuple()。但是,Boost.Fusion 提供了超出標(biāo)準(zhǔn)庫(kù)中所提供功能的附加功能。
示例 50.2。使用 boost::fusion::for_each() 迭代元組
#include <boost/fusion/tuple.hpp> #include <boost/fusion/algorithm.hpp> #include <string> #include <iostream> using namespace boost::fusion; struct print { template <typename T> void operator()(const T &t) const { std::cout << std::boolalpha << t << '\n'; } }; int main() { typedef tuple<int, std::string, bool, double> tuple_type; tuple_type t{10, "Boost", true, 3.14}; for_each(t, print{}); }
示例 50.2 介紹了算法 boost::fusion::for_each(),它迭代 Fusion 容器。此處使用該函數(shù)將元組 t 中的值寫(xiě)入標(biāo)準(zhǔn)輸出。
boost::fusion::for_each() 旨在像 std::for_each() 一樣工作。 std::for_each() 僅迭代同類(lèi)容器,而 boost::fusion::for_each() 適用于異構(gòu)容器。您將容器而不是迭代器傳遞給 boost::fusion::for_each()。如果您不想遍歷容器中的所有元素,可以使用視圖。
示例 50.3。使用 boost::fusion::filter_view 過(guò)濾 Fusion 容器
#include <boost/fusion/tuple.hpp> #include <boost/fusion/view.hpp> #include <boost/fusion/algorithm.hpp> #include <boost/type_traits.hpp> #include <boost/mpl/arg.hpp> #include <string> #include <iostream> using namespace boost::fusion; struct print { template <typename T> void operator()(const T &t) const { std::cout << std::boolalpha << t << '\n'; } }; int main() { typedef tuple<int, std::string, bool, double> tuple_type; tuple_type t{10, "Boost", true, 3.14}; filter_view<tuple_type, boost::is_integral<boost::mpl::arg<1>>> v{t}; for_each(v, print{}); }
Boost.Fusion 提供了視圖,它像容器一樣工作但不存儲(chǔ)數(shù)據(jù)。使用視圖,可以以不同方式訪(fǎng)問(wèn)容器中的數(shù)據(jù)。視圖類(lèi)似于來(lái)自 Boost.Range 的適配器。然而,雖然來(lái)自 Boost.Range 的適配器只能應(yīng)用于一個(gè)容器,但來(lái)自 Boost.Fusion 的視圖可以跨越來(lái)自多個(gè)容器的數(shù)據(jù)。
示例 50.3 使用類(lèi) boost::fusion::filter_view 來(lái)過(guò)濾元組 t。過(guò)濾器指示 boost::fusion::for_each() 僅寫(xiě)入基于整數(shù)類(lèi)型的元素。
boost::fusion::filter_view 期望第一個(gè)模板參數(shù)是要過(guò)濾的容器類(lèi)型。第二個(gè)模板參數(shù)必須是過(guò)濾元素的謂詞。謂詞必須根據(jù)元素的類(lèi)型過(guò)濾元素。
該庫(kù)之所以稱(chēng)為 Boost.Fusion,是因?yàn)樗Y(jié)合了兩個(gè)世界:C++ 程序在運(yùn)行時(shí)處理值,在編譯時(shí)處理類(lèi)型。對(duì)于開(kāi)發(fā)人員來(lái)說(shuō),運(yùn)行時(shí)的值通常更為重要。來(lái)自標(biāo)準(zhǔn)庫(kù)的大多數(shù)工具在運(yùn)行時(shí)處理值。為了在編譯時(shí)處理類(lèi)型,使用了模板元編程。值在運(yùn)行時(shí)根據(jù)其他值進(jìn)行處理,而類(lèi)型在編譯時(shí)根據(jù)其他類(lèi)型進(jìn)行處理。 Boost.Fusion 允許您根據(jù)類(lèi)型處理值。
傳遞給 boost::fusion::filter_view 的第二個(gè)模板參數(shù)是一個(gè)謂詞,它將應(yīng)用于元組中的每個(gè)類(lèi)型。謂詞需要一個(gè)類(lèi)型作為參數(shù),如果該類(lèi)型應(yīng)該是視圖的一部分,則返回 true。如果返回 false,則過(guò)濾掉該類(lèi)型。
示例 50.3 使用來(lái)自 Boost.TypeTraits 的類(lèi) boost::is_integral。 boost::is_integral 是一個(gè)檢查類(lèi)型是否為整數(shù)的模板。因?yàn)楸仨殞⒛0鍏?shù)傳遞給 boost::fusion::filter_view,所以使用來(lái)自 Boost.MPL 的占位符 boost::mpl::arg<1> 來(lái)創(chuàng)建 lambda 函數(shù)。 boost::mpl::arg<1> 類(lèi)似于來(lái)自 Boost.Phoenix 的 boost::phoenix::place_holders::arg1。在示例 50.3 中,視圖 v 將僅包含元組中的 int 和 bool 元素,因此,該示例會(huì)將 10 和 true 寫(xiě)入標(biāo)準(zhǔn)輸出。
示例 50.4。使用迭代器訪(fǎng)問(wèn) Fusion 容器中的元素
#include <boost/fusion/tuple.hpp> #include <boost/fusion/iterator.hpp> #include <boost/mpl/int.hpp> #include <string> #include <iostream> using namespace boost::fusion; int main() { typedef tuple<int, std::string, bool, double> tuple_type; tuple_type t{10, "Boost", true, 3.14}; auto it = begin(t); std::cout << *it << '\n'; auto it2 = advance<boost::mpl::int_<2>>(it); std::cout << std::boolalpha << *it2 << '\n'; }
在看過(guò) boost::fusion::tuple 和 boost::fusion::for_each() 之后,在示例 50.4 中找到迭代器應(yīng)該不足為奇。 Boost.Fusion 提供了幾個(gè)獨(dú)立的函數(shù),例如 boost::fusion::begin() 和 boost::fusion::advance(),它們的工作方式類(lèi)似于標(biāo)準(zhǔn)庫(kù)中的同名函數(shù)。
迭代器要遞增的步數(shù)作為模板參數(shù)傳遞給 boost::fusion::advance()。該示例再次使用來(lái)自 Boost.MPL 的 boost::mpl::int_。
boost::fusion::advance() 返回一個(gè)與傳遞給函數(shù)的迭代器類(lèi)型不同的迭代器。這就是示例 50.4 使用第二個(gè)迭代器 it2 的原因。您不能將 boost::fusion::advance() 的返回值分配給第一個(gè)迭代器 it。示例 50.4 將 10 和 true 寫(xiě)入標(biāo)準(zhǔn)輸出。
除了示例中介紹的函數(shù)之外,Boost.Fusion 還提供了與迭代器一起使用的其他函數(shù)。其中包括:boost::fusion::end()、boost::fusion::distance()、boost::fusion::next() 和 boost::fusion::prior()。
示例 50.5。具有 boost::fusion::vector 的異構(gòu)向量
#include <boost/fusion/container.hpp> #include <boost/fusion/sequence.hpp> #include <boost/mpl/int.hpp> #include <string> #include <iostream> using namespace boost::fusion; int main() { typedef vector<int, std::string, bool, double> vector_type; vector_type v{10, "Boost", true, 3.14}; std::cout << at<boost::mpl::int_<0>>(v) << '\n'; auto v2 = push_back(v, 'X'); std::cout << size(v) << '\n'; std::cout << size(v2) << '\n'; std::cout << back(v2) << '\n'; }
到目前為止,我們只看到了一個(gè)異構(gòu)容器,boost::fusion::tuple。示例 50.5 引入了另一個(gè)容器,boost::fusion::vector。
boost::fusion::vector 是一個(gè)向量:通過(guò)索引訪(fǎng)問(wèn)元素。訪(fǎng)問(wèn)不是使用運(yùn)算符 operator[] 實(shí)現(xiàn)的。相反,它是使用獨(dú)立函數(shù) boost::fusion::at() 實(shí)現(xiàn)的。索引作為用 boost::mpl::int_ 包裝的模板參數(shù)傳遞。
此示例將一個(gè) char 類(lèi)型的新元素添加到向量中。這是通過(guò)獨(dú)立函數(shù) boost::fusion::push_back() 完成的。兩個(gè)參數(shù)被傳遞給 boost::fusion::push_back():要添加元素的向量和要添加的值。
boost::fusion::push_back() 返回一個(gè)新向量。矢量 v 沒(méi)有改變。新向量是添加了元素的原始向量的副本。
此示例使用 boost::fusion::size() 獲取向量 v 和 v2 中的元素?cái)?shù)量,并將這兩個(gè)值寫(xiě)入標(biāo)準(zhǔn)輸出。該程序顯示 4 和 5。然后調(diào)用 boost::fusion::back() 獲取 v2 中的最后一個(gè)元素并將其寫(xiě)入標(biāo)準(zhǔn)輸出,在本例中值為 X。
如果您更仔細(xì)地查看示例 50.5,您會(huì)注意到 boost::fusion::tuple 和 boost::fusion::vector 之間沒(méi)有區(qū)別;他們是一樣的。因此,示例 50.5 也可以與 boost::fusion::tuple 一起使用。
Boost.Fusion 提供了額外的異構(gòu)容器,包括:boost::fusion::deque、boost::fusion::list 和 boost::fusion::set。示例 50.6 引入了 boost::fusion::map,它是鍵/值對(duì)的容器。
示例 50.6。帶有 boost::fusion::map 的異構(gòu)映射
#include <boost/fusion/container.hpp> #include <boost/fusion/sequence.hpp> #include <boost/fusion/algorithm.hpp> #include <string> #include <iostream> using namespace boost::fusion; int main() { auto m = make_map<int, std::string, bool, double>("Boost", 10, 3.14, true); if (has_key<std::string>(m)) std::cout << at_key<std::string>(m) << '\n'; auto m2 = erase_key<std::string>(m); auto m3 = push_back(m2, make_pair<float>('X')); std::cout << std::boolalpha << has_key<std::string>(m3) << '\n'; }
示例 50.6 使用 boost::fusion::map() 創(chuàng)建了一個(gè)異構(gòu)映射。地圖的類(lèi)型是 boost::fusion::map,由于關(guān)鍵字 auto,它沒(méi)有在示例中寫(xiě)出。
boost::fusion::map 類(lèi)型的映射像 std::map 一樣存儲(chǔ)鍵/值對(duì)。但是,F(xiàn)usion 映射中的鍵是類(lèi)型。鍵/值對(duì)由一個(gè)類(lèi)型和一個(gè)映射到該類(lèi)型的值組成。該值可能是與鍵不同的類(lèi)型。在示例 50.6 中,字符串“Boost”映射到鍵 int。
創(chuàng)建映射后,調(diào)用 boost::fusion::has_key() 以檢查鍵 std::string 是否存在。然后,調(diào)用 boost::fusion::at_key() 以獲取映射到該鍵的值。因?yàn)閿?shù)字 10 映射到 std::string,所以它被寫(xiě)入標(biāo)準(zhǔn)輸出。
然后使用 boost::fusion::erase_key() 擦除鍵/值對(duì)。這不會(huì)改變地圖 m。 boost::fusion::erase_key() 返回一個(gè)新映射,該映射缺少已擦除的鍵/值對(duì)。
對(duì) boost::fusion::push_back() 的調(diào)用將一個(gè)新的鍵/值對(duì)添加到映射中。鍵是浮點(diǎn)數(shù),值是“X”。調(diào)用 boost::fusion::make_pair() 來(lái)創(chuàng)建新的鍵/值對(duì)。此函數(shù)類(lèi)似于 std::make_pair()。
最后,再次調(diào)用 boost::fusion::has_key() 以檢查映射是否具有鍵 std::string。因?yàn)樗驯粍h除,所以返回 false。
請(qǐng)注意,在調(diào)用 boost::fusion::at_key() 之前,您不需要調(diào)用 boost::fusion::has_key() 來(lái)檢查密鑰是否存在。如果傳遞給 boost::fusion::at_key() 的鍵在映射中不存在,則會(huì)出現(xiàn)編譯器錯(cuò)誤。
示例 50.7。結(jié)構(gòu)融合適配器
#include <boost/fusion/adapted.hpp> #include <boost/fusion/sequence.hpp> #include <boost/mpl/int.hpp> #include <iostream> struct strct { int i; double d; }; BOOST_FUSION_ADAPT_STRUCT(strct, (int, i) (double, d) ) using namespace boost::fusion; int main() { strct s = {10, 3.14}; std::cout << at<boost::mpl::int_<0>>(s) << '\n'; std::cout << back(s) << '\n'; }
Boost.Fusion 提供了幾個(gè)宏,讓您可以將結(jié)構(gòu)用作 Fusion 容器。這是可能的,因?yàn)榻Y(jié)構(gòu)可以充當(dāng)異構(gòu)容器。由于宏 BOOST_FUSION_ADAPT_STRUCT,示例 50.7 定義了一個(gè)可以用作 Fusion 容器的結(jié)構(gòu)。這使得可以使用具有 boost::fusion::at() 或 boost::fusion::back() 等函數(shù)的結(jié)構(gòu)。
示例 50.8。對(duì) std::pair 的融合支持
#include <boost/fusion/adapted.hpp> #include <boost/fusion/sequence.hpp> #include <boost/mpl/int.hpp> #include <utility> #include <iostream> using namespace boost::fusion; int main() { auto p = std::make_pair(10, 3.14); std::cout << at<boost::mpl::int_<0>>(p) << '\n'; std::cout << back(p) << '\n'; }
Boost.Fusion 無(wú)需使用宏即可支持 std::pair 和 boost::tuple 等結(jié)構(gòu)。您只需包含頭文件 boost/fusion/adapted.hpp(參見(jiàn)示例 50.8)。
#include <boost/math/constants/constants.hpp> #include <iostream> struct animal { std::string name; int legs; bool has_tail; }; struct important_numbers { const float pi = boost::math::constants::pi<float>(); const double e = boost::math::constants::e<double>(); }; template <class T> void debug(const T &t) { // TODO: Write member variables of t to standard output. } int main() { animal a{ "cat", 4, true }; debug(a); important_numbers in; debug(in); }
到此這篇關(guān)于C++ Boost Fusion創(chuàng)建異構(gòu)容器詳解的文章就介紹到這了,更多相關(guān)C++ Boost Fusion內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解在C++中顯式默認(rèn)設(shè)置的函數(shù)和已刪除的函數(shù)的方法
這篇文章主要介紹了在C++中顯式默認(rèn)設(shè)置的函數(shù)和已刪除的函數(shù)的方法,文中講到了C++11標(biāo)準(zhǔn)中的新特性,需要的朋友可以參考下2016-01-01