C++ Boost Fusion创建异构容器详解

目录
  • 一、说明
  • 二、示例和代码

一、说明

标准库提供了许多容器,它们有一个共同点:它们是同类的。也就是说,标准库中的容器只能存储一种类型的元素。 std::vector<int> 类型的向量只能存储 int 值,而 std::vector<std::string> 类型的向量只能存储字符串。

Boost.Fusion 使创建异构容器成为可能。例如,您可以创建一个向量,其第一个元素是 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';
}

Example50.1

示例 50.1 定义了一个由 int、std::string、bool 和 double 组成的元组。该元组基于 boost:fusion::tuple。在示例 50.1 中,元组随后被实例化、初始化,并使用 boost::fusion::get() 检索各种元素并写入标准输出。函数 boost::fusion::get() 类似于 std::get(),它访问 std::tuple 中的元素。

融合元组与标准库中的元组没有区别。因此,Boost.Fusion 提供函数 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 容器。此处使用该函数将元组 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 提供了视图,它像容器一样工作但不存储数据。使用视图,可以以不同方式访问容器中的数据。视图类似于来自 Boost.Range 的适配器。然而,虽然来自 Boost.Range 的适配器只能应用于一个容器,但来自 Boost.Fusion 的视图可以跨越来自多个容器的数据。

示例 50.3 使用类 boost::fusion::filter_view 来过滤元组 t。过滤器指示 boost::fusion::for_each() 仅写入基于整数类型的元素。

boost::fusion::filter_view 期望第一个模板参数是要过滤的容器类型。第二个模板参数必须是过滤元素的谓词。谓词必须根据元素的类型过滤元素。

该库之所以称为 Boost.Fusion,是因为它结合了两个世界:C++ 程序在运行时处理值,在编译时处理类型。对于开发人员来说,运行时的值通常更为重要。来自标准库的大多数工具在运行时处理值。为了在编译时处理类型,使用了模板元编程。值在运行时根据其他值进行处理,而类型在编译时根据其他类型进行处理。 Boost.Fusion 允许您根据类型处理值。

传递给 boost::fusion::filter_view 的第二个模板参数是一个谓词,它将应用于元组中的每个类型。谓词需要一个类型作为参数,如果该类型应该是视图的一部分,则返回 true。如果返回 false,则过滤掉该类型。

示例 50.3 使用来自 Boost.TypeTraits 的类 boost::is_integral。 boost::is_integral 是一个检查类型是否为整数的模板。因为必须将模板参数传递给 boost::fusion::filter_view,所以使用来自 Boost.MPL 的占位符 boost::mpl::arg<1> 来创建 lambda 函数。 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 提供了几个独立的函数,例如 boost::fusion::begin() 和 boost::fusion::advance(),它们的工作方式类似于标准库中的同名函数。

迭代器要递增的步数作为模板参数传递给 boost::fusion::advance()。该示例再次使用来自 Boost.MPL 的 boost::mpl::int_。

boost::fusion::advance() 返回一个与传递给函数的迭代器类型不同的迭代器。这就是示例 50.4 使用第二个迭代器 it2 的原因。您不能将 boost::fusion::advance() 的返回值分配给第一个迭代器 it。示例 50.4 将 10 和 true 写入标准输出。

除了示例中介绍的函数之外,Boost.Fusion 还提供了与迭代器一起使用的其他函数。其中包括: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[] 实现的。相反,它是使用独立函数 boost::fusion::at() 实现的。索引作为用 boost::mpl::int_ 包装的模板参数传递。

此示例将一个 char 类型的新元素添加到向量中。这是通过独立函数 boost::fusion::push_back() 完成的。两个参数被传递给 boost::fusion::push_back():要添加元素的向量和要添加的值。

boost::fusion::push_back() 返回一个新向量。矢量 v 没有改变。新向量是添加了元素的原始向量的副本。

此示例使用 boost::fusion::size() 获取向量 v 和 v2 中的元素数量,并将这两个值写入标准输出。该程序显示 4 和 5。然后调用 boost::fusion::back() 获取 v2 中的最后一个元素并将其写入标准输出,在本例中值为 X。

如果您更仔细地查看示例 50.5,您会注意到 boost::fusion::tuple 和 boost::fusion::vector 之间没有区别;他们是一样的。因此,示例 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';
}

Example50.6

示例 50.6 使用 boost::fusion::map() 创建了一个异构映射。地图的类型是 boost::fusion::map,由于关键字 auto,它没有在示例中写出。

boost::fusion::map 类型的映射像 std::map 一样存储键/值对。但是,Fusion 映射中的键是类型。键/值对由一个类型和一个映射到该类型的值组成。该值可能是与键不同的类型。在示例 50.6 中,字符串“Boost”映射到键 int。

创建映射后,调用 boost::fusion::has_key() 以检查键 std::string 是否存在。然后,调用 boost::fusion::at_key() 以获取映射到该键的值。因为数字 10 映射到 std::string,所以它被写入标准输出。

然后使用 boost::fusion::erase_key() 擦除键/值对。这不会改变地图 m。 boost::fusion::erase_key() 返回一个新映射,该映射缺少已擦除的键/值对。

对 boost::fusion::push_back() 的调用将一个新的键/值对添加到映射中。键是浮点数,值是“X”。调用 boost::fusion::make_pair() 来创建新的键/值对。此函数类似于 std::make_pair()。

最后,再次调用 boost::fusion::has_key() 以检查映射是否具有键 std::string。因为它已被删除,所以返回 false。

请注意,在调用 boost::fusion::at_key() 之前,您不需要调用 boost::fusion::has_key() 来检查密钥是否存在。如果传递给 boost::fusion::at_key() 的键在映射中不存在,则会出现编译器错误。

示例 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() 等函数的结构。

示例 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创建异构容器详解的文章就介绍到这了,更多相关C++ Boost Fusion内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++ Boost Foreach超详细分析讲解

    目录 一.说明 二.示例代码 2.1 最简单的代码 2.2 使用BOOST_FOREACH与BOOST_REVERSE_FOREACH 三.BOOST_FOREACH特点和应用范围 四.遍历循环控制 一.说明 Boost.Foreach Boost.Foreach 提供了一个宏来模拟 C++11 中基于范围的 for 循环.您可以使用在 boost/foreach.hpp 中定义的宏 BOOST_FOREACH 来迭代序列而不使用迭代器.如果你的开发环境支持C++11,可以忽略Boost.For

  • C++ Boost Coroutine使用协程详解

    目录 一.说明语言扩展 二.库Boost.Coroutine 三.示例和代码 一.说明语言扩展 以下库扩展了编程语言 C++. Boost.Coroutine 使得在 C++ 中使用协程成为可能——其他编程语言通常通过关键字 yield 支持. Boost.Foreach 提供了一个基于范围的 for 循环,它是在 C++11 中添加到语言中的. Boost.Parameter 允许您以名称/值对的形式并以任何顺序传递参数——例如,这在 Python 中是允许的. Boost.Conversio

  • C++ Boost Parameter超详细讲解

    目录 一.说明 二.示例代码 一.说明 Boost.Parameter 使得将参数作为键/值对传递成为可能.除了支持函数参数外,该库还支持模板参数. Boost.Parameter 在您使用长参数列表并且参数的顺序和含义难以记住时特别有用.键/值对使得以任何顺序传递参数成为可能.因为每一个值都是通过一个键来传递的,所以各种值的含义也更加清晰. 二.示例代码 示例 53.1.作为键/值对的函数参数 #include <boost/parameter.hpp> #include <strin

  • C++ Boost System超详细讲解

    目录 一.说明 二.关于 Boost.System库 一.说明 以下库支持错误处理. Boost.System 提供类来描述和识别错误.自 C++11 以来,这些类已成为标准库的一部分. Boost.Exception 使得在抛出异常后附加数据成为可能. 二.关于 Boost.System库 Boost.System Boost.System 是一个库,本质上定义了四个类来识别错误.所有四个类都已添加到 C++11 的标准库中.如果您的开发环境支持 C++11,则无需使用 Boost.Syste

  • C++ boost thread库用法详细讲解

    目录 一.说明 二.boost::thread的几个函数 三.构造 一.说明 boost::thread的六种使用方法总结,本文初步介绍线程的函数.构造.执行的详细解释. 二.boost::thread的几个函数 函数 功能 join() 让主进程等待子线程执行完毕后再继续执行 get_id() 获得线程的 id 号 detach() 标线程就成为了守护线程,驻留后台运行 bool joinable() 是否已经启动,为 join() thread::join()是个简单暴力的方法,主线程等待子

  • C++ Boost Accumulators累加器详细讲解

    Boost.Accumulators Boost.Accumulators 提供了处理样本的类.例如,您可以找到最大或最小的样本,或者计算所有样本的总和.虽然标准库支持其中一些操作,但 Boost.Accumulators 还支持统计计算,例如均值和标准差. 该库称为 Boost.Accumulators,因为累加器是一个基本概念.累加器是一个容器,每次插入一个值时都会计算出一个新的结果.该值不一定存储在累加器中.相反,累加器在输入新值时不断更新中间结果. Boost.Accumulators

  • C++ Boost Conversion超详细讲解

    目录 一.说明 二.示例和代码 三.更多示例代码 一.说明 Boost.Conversion 在头文件 boost/cast.hpp 中定义了转换运算符 boost::polymorphic_cast 和 boost::polymorphic_downcast.它们旨在更精确地处理类型转换——通常使用 dynamic_cast 完成. 库由两个文件组成.分别在boost/cast.hpp文件中定义了boost::polymorphic_cast和boost::polymorphic_downca

  • C++ Boost EnableIf函数使用介绍

    目录 一.说明 二.Boost.EnableIf的示例 练习 一.说明 Boost.EnableIf Boost.Enable If 可以禁用重载函数模板或专用类模板.禁用意味着编译器忽略相应的模板.这有助于防止出现模棱两可的情况,即编译器不知道要使用哪个重载函数模板.它还可以更轻松地定义不仅可用于特定类型而且可用于一组类型的模板. 从 C++11 开始,Boost.EnableIf 已经成为标准库的一部分.您可以在不使用 Boost 库的情况下调用本章介绍的函数:只需包含头文件 type_tr

  • C++ Boost Exception超详细讲解

    Boost.Exception 库提供了一种新的异常类型 boost::exception,它允许您在抛出异常后将数据添加到异常中.此类型在 boost/exception/exception.hpp 中定义.由于 Boost.Exception 将其类和函数分布在多个头文件中,以下示例访问主头文件 boost/exception/all.hpp 以避免一个接一个地包含头文件. Boost.Exception 支持 C++11 标准的机制,该机制将异常从一个线程传输到另一个线程. boost::

  • C++ Boost Fusion创建异构容器详解

    目录 一.说明 二.示例和代码 一.说明 标准库提供了许多容器,它们有一个共同点:它们是同类的.也就是说,标准库中的容器只能存储一种类型的元素. std::vector<int> 类型的向量只能存储 int 值,而 std::vector<std::string> 类型的向量只能存储字符串. Boost.Fusion 使创建异构容器成为可能.例如,您可以创建一个向量,其第一个元素是 int,第二个元素是字符串.此外,Boost.Fusion 提供了处理异构容器的算法.您可以将 Bo

  • C++ 标准模板库 STL 顺序容器详解

    C++ 标准模板库 STL 顺序容器 容器 数据结构 顺序性 重复性 支持迭代器 vector 动态数组 无序 可重复 随机访问迭代器 deque 双向队列 无序 可重复 随机访问迭代器 list 双向链表 无序 可重复 双向迭代器 动态数组 vector ​ vector #include <vector> 动态数组:其元素在内存中是连续存放的,随机存取任何元素都可以在常数时间内完成,在该容器的尾部增删元素也几乎能够在常数时间内完成具有较好的性能. ​ 一个 vector 常用函数使用实例如

  • C/C++ 动态数组的创建的实例详解

    C/C++ 动态数组的创建的实例详解 在C++语言中,二维动态数组主要使用指针的方法建立,以建立一个整数二维数组为例: #include<iostream> #include<string> #include<malloc.h> using namespace std; int main(int argc,char **argv) { ///*int a[2][3]={{1,2,3},{4,5,6}}; //cout<<sizeof(a+1)<<

  • java存储以及java对象创建的流程(详解)

    java存储: 1)寄存器:这是最快的存储区,位于处理器的内部.但是寄存器的数量有限,所以寄存器根据需求进行分配.我们不能直接进行操作. 2)堆栈:位于通用RAM中,可以通过堆栈指针从处理器那里获取直接支持.堆栈指针往下移动,则分配新的内存.网上移动,则释放内存.但是 在创建程序的时候必须知道存储在堆栈中的所有项的具体生命周期,以便上下的移动指针.一般存储基本类型和java对象引用. 3)堆:位于通用RAM中,存放所有的java对象,不需要知道具体的生命周期. 4)常量存储:常量值通常直接存放在

  • DJango的创建和使用详解(默认数据库sqlite3)

    1.安装虚拟环境 虚拟环境是真实python环境的复制版本. 安装虚拟环境的命令: 1)sudo pip install virtualenv #安装虚拟环境 2)sudo pip install virtualenvwrapper #安装虚拟环境扩展包 3)编辑家目录下面的.bashrc文件,添加下面两行. export WORKON_HOME=$HOME/.virtualenvs source /usr/local/bin/virtualenvwrapper.sh 4)使用source .b

  • C++ boost库的安装过程详解

    Windows安装boost库 下载链接:https://www.boost.org/ 学习链接:https://theboostcpplibraries.com/ 1,下载解压,我的目录"C:\Program Files (x86)\Microsoft Visual Studio\2017" 2,以管理员身份运行"适用于 VS 2017 的 x64 本机工具命令提示" 3,执行以下命令进行编译: cd /d "C:\Program Files (x86)

  • Java并发编程之同步容器与并发容器详解

    一.同步容器  1.Vector-->ArrayList vector 是线程(Thread)同步(Synchronized)的,所以它也是线程安全的: Arraylist是线程异步(ASynchronized)的,是不安全的: 2.Hashtable-->HashMap Hashtable是synchronized,这意味着Hashtable是线程安全的,多个线程可以共享一个Hashtable: HashMap是非synchronized,这意味着HashMap是非线程安全的; 3.Coll

  • oracle创建用户过程详解

    1.首先用管理员用户登陆sqlplus: sqlplus "sysman/安装时设置的密码" 2.创建用户 create user userName identified by password; 创建用户 userName,密码为 password 3.给用户授权 grant dba to userName; --授予DBA权限 grant unlimited tablespace to userName;--授予不限制的表空间 grant select any table to u

  • Android AlertDialog六种创建方式案例详解

    目录 一.setMessage:设置对话框内容为简单文本内容 二.setItem:设置文本框内容为简单列表项 三.setSingleChoiceItems()设置对话框内容为单选列表项 四.setMultiChoiceItems()设置对话框内容为多选项列表 五.setAdapter()设置对话框内容为自定义列表项(这里是一个布局) 六.setView()设置对话框为自定义View 创建AlertDialog的步骤: 创建AlertDialog.Builder对象 调用Builder对象的set

随机推荐