C++ Boost Fusion創(chuàng)建異構容器詳解
一、說明
標準庫提供了許多容器,它們有一個共同點:它們是同類的。也就是說,標準庫中的容器只能存儲一種類型的元素。 std::vector<int> 類型的向量只能存儲 int 值,而 std::vector<std::string> 類型的向量只能存儲字符串。
Boost.Fusion 使創(chuàng)建異構容器成為可能。例如,您可以創(chuàng)建一個向量,其第一個元素是 int,第二個元素是字符串。此外,Boost.Fusion 提供了處理異構容器的算法。您可以將 Boost.Fusion 視為異構容器的標準庫。
嚴格來說,從C++11開始,標準庫就提供了一個異構容器,std::tuple。您可以對存儲在元組中的值使用不同的類型。 Boost.Fusion 中的 boost:fusion::tuple 是類似的類型。雖然標準庫沒有提供更多,但元組只是 Boost.Fusion 的起點。
二、示例和代碼
示例 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 定義了一個由 int、std::string、bool 和 double 組成的元組。該元組基于 boost:fusion::tuple。在示例 50.1 中,元組隨后被實例化、初始化,并使用 boost::fusion::get() 檢索各種元素并寫入標準輸出。函數(shù) boost::fusion::get() 類似于 std::get(),它訪問 std::tuple 中的元素。
融合元組與標準庫中的元組沒有區(qū)別。因此,Boost.Fusion 提供函數(shù) boost::fusion::make_tuple() 就不足為奇了,它的工作方式類似于 std::make_tuple()。但是,Boost.Fusion 提供了超出標準庫中所提供功能的附加功能。
示例 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 中的值寫入標準輸出。
boost::fusion::for_each() 旨在像 std::for_each() 一樣工作。 std::for_each() 僅迭代同類容器,而 boost::fusion::for_each() 適用于異構容器。您將容器而不是迭代器傳遞給 boost::fusion::for_each()。如果您不想遍歷容器中的所有元素,可以使用視圖。
示例 50.3。使用 boost::fusion::filter_view 過濾 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 提供了視圖,它像容器一樣工作但不存儲數(shù)據(jù)。使用視圖,可以以不同方式訪問容器中的數(shù)據(jù)。視圖類似于來自 Boost.Range 的適配器。然而,雖然來自 Boost.Range 的適配器只能應用于一個容器,但來自 Boost.Fusion 的視圖可以跨越來自多個容器的數(shù)據(jù)。
示例 50.3 使用類 boost::fusion::filter_view 來過濾元組 t。過濾器指示 boost::fusion::for_each() 僅寫入基于整數(shù)類型的元素。
boost::fusion::filter_view 期望第一個模板參數(shù)是要過濾的容器類型。第二個模板參數(shù)必須是過濾元素的謂詞。謂詞必須根據(jù)元素的類型過濾元素。
該庫之所以稱為 Boost.Fusion,是因為它結合了兩個世界:C++ 程序在運行時處理值,在編譯時處理類型。對于開發(fā)人員來說,運行時的值通常更為重要。來自標準庫的大多數(shù)工具在運行時處理值。為了在編譯時處理類型,使用了模板元編程。值在運行時根據(jù)其他值進行處理,而類型在編譯時根據(jù)其他類型進行處理。 Boost.Fusion 允許您根據(jù)類型處理值。
傳遞給 boost::fusion::filter_view 的第二個模板參數(shù)是一個謂詞,它將應用于元組中的每個類型。謂詞需要一個類型作為參數(shù),如果該類型應該是視圖的一部分,則返回 true。如果返回 false,則過濾掉該類型。
示例 50.3 使用來自 Boost.TypeTraits 的類 boost::is_integral。 boost::is_integral 是一個檢查類型是否為整數(shù)的模板。因為必須將模板參數(shù)傳遞給 boost::fusion::filter_view,所以使用來自 Boost.MPL 的占位符 boost::mpl::arg<1> 來創(chuàng)建 lambda 函數(shù)。 boost::mpl::arg<1> 類似于來自 Boost.Phoenix 的 boost::phoenix::place_holders::arg1。在示例 50.3 中,視圖 v 將僅包含元組中的 int 和 bool 元素,因此,該示例會將 10 和 true 寫入標準輸出。
示例 50.4。使用迭代器訪問 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'; }
在看過 boost::fusion::tuple 和 boost::fusion::for_each() 之后,在示例 50.4 中找到迭代器應該不足為奇。 Boost.Fusion 提供了幾個獨立的函數(shù),例如 boost::fusion::begin() 和 boost::fusion::advance(),它們的工作方式類似于標準庫中的同名函數(shù)。
迭代器要遞增的步數(shù)作為模板參數(shù)傳遞給 boost::fusion::advance()。該示例再次使用來自 Boost.MPL 的 boost::mpl::int_。
boost::fusion::advance() 返回一個與傳遞給函數(shù)的迭代器類型不同的迭代器。這就是示例 50.4 使用第二個迭代器 it2 的原因。您不能將 boost::fusion::advance() 的返回值分配給第一個迭代器 it。示例 50.4 將 10 和 true 寫入標準輸出。
除了示例中介紹的函數(shù)之外,Boost.Fusion 還提供了與迭代器一起使用的其他函數(shù)。其中包括:boost::fusion::end()、boost::fusion::distance()、boost::fusion::next() 和 boost::fusion::prior()。
示例 50.5。具有 boost::fusion::vector 的異構向量
#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'; }
到目前為止,我們只看到了一個異構容器,boost::fusion::tuple。示例 50.5 引入了另一個容器,boost::fusion::vector。
boost::fusion::vector 是一個向量:通過索引訪問元素。訪問不是使用運算符 operator[] 實現(xiàn)的。相反,它是使用獨立函數(shù) boost::fusion::at() 實現(xiàn)的。索引作為用 boost::mpl::int_ 包裝的模板參數(shù)傳遞。
此示例將一個 char 類型的新元素添加到向量中。這是通過獨立函數(shù) boost::fusion::push_back() 完成的。兩個參數(shù)被傳遞給 boost::fusion::push_back():要添加元素的向量和要添加的值。
boost::fusion::push_back() 返回一個新向量。矢量 v 沒有改變。新向量是添加了元素的原始向量的副本。
此示例使用 boost::fusion::size() 獲取向量 v 和 v2 中的元素數(shù)量,并將這兩個值寫入標準輸出。該程序顯示 4 和 5。然后調用 boost::fusion::back() 獲取 v2 中的最后一個元素并將其寫入標準輸出,在本例中值為 X。
如果您更仔細地查看示例 50.5,您會注意到 boost::fusion::tuple 和 boost::fusion::vector 之間沒有區(qū)別;他們是一樣的。因此,示例 50.5 也可以與 boost::fusion::tuple 一起使用。
Boost.Fusion 提供了額外的異構容器,包括:boost::fusion::deque、boost::fusion::list 和 boost::fusion::set。示例 50.6 引入了 boost::fusion::map,它是鍵/值對的容器。
示例 50.6。帶有 boost::fusion::map 的異構映射
#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)建了一個異構映射。地圖的類型是 boost::fusion::map,由于關鍵字 auto,它沒有在示例中寫出。
boost::fusion::map 類型的映射像 std::map 一樣存儲鍵/值對。但是,F(xiàn)usion 映射中的鍵是類型。鍵/值對由一個類型和一個映射到該類型的值組成。該值可能是與鍵不同的類型。在示例 50.6 中,字符串“Boost”映射到鍵 int。
創(chuàng)建映射后,調用 boost::fusion::has_key() 以檢查鍵 std::string 是否存在。然后,調用 boost::fusion::at_key() 以獲取映射到該鍵的值。因為數(shù)字 10 映射到 std::string,所以它被寫入標準輸出。
然后使用 boost::fusion::erase_key() 擦除鍵/值對。這不會改變地圖 m。 boost::fusion::erase_key() 返回一個新映射,該映射缺少已擦除的鍵/值對。
對 boost::fusion::push_back() 的調用將一個新的鍵/值對添加到映射中。鍵是浮點數(shù),值是“X”。調用 boost::fusion::make_pair() 來創(chuàng)建新的鍵/值對。此函數(shù)類似于 std::make_pair()。
最后,再次調用 boost::fusion::has_key() 以檢查映射是否具有鍵 std::string。因為它已被刪除,所以返回 false。
請注意,在調用 boost::fusion::at_key() 之前,您不需要調用 boost::fusion::has_key() 來檢查密鑰是否存在。如果傳遞給 boost::fusion::at_key() 的鍵在映射中不存在,則會出現(xiàn)編譯器錯誤。
示例 50.7。結構融合適配器
#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 提供了幾個宏,讓您可以將結構用作 Fusion 容器。這是可能的,因為結構可以充當異構容器。由于宏 BOOST_FUSION_ADAPT_STRUCT,示例 50.7 定義了一個可以用作 Fusion 容器的結構。這使得可以使用具有 boost::fusion::at() 或 boost::fusion::back() 等函數(shù)的結構。
示例 50.8。對 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 無需使用宏即可支持 std::pair 和 boost::tuple 等結構。您只需包含頭文件 boost/fusion/adapted.hpp(參見示例 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); }
到此這篇關于C++ Boost Fusion創(chuàng)建異構容器詳解的文章就介紹到這了,更多相關C++ Boost Fusion內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
詳解在C++中顯式默認設置的函數(shù)和已刪除的函數(shù)的方法
這篇文章主要介紹了在C++中顯式默認設置的函數(shù)和已刪除的函數(shù)的方法,文中講到了C++11標準中的新特性,需要的朋友可以參考下2016-01-01