返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++BoostMultiIndex使用详细介绍
  • 562
分享到

C++BoostMultiIndex使用详细介绍

C++BoostMultiIndexC++MultiIndex 2022-11-13 19:11:55 562人浏览 安东尼
摘要

目录一、关于BOOST的容器二、Boost.MultiIndex练习一、关于BOOST的容器 容器是 c++ 中最有用的数据结构之一。标准库提供了许多容器,而 Boost 库提供的更

一、关于BOOST的容器

容器是 c++ 中最有用的数据结构之一。标准库提供了许多容器,而 Boost 库提供的更多。

  • Boost.MultiIndex 更进一步:这个库中的容器可以同时支持来自其他容器的多个接口。来自 Boost.MultiIndex 的容器就像合并的容器,并提供了与它们合并的所有容器的优点。
  • Boost.Bimap 基于 Boost.MultiIndex。它提供了一个类似于 std::unordered_map 的容器,不同之处在于可以从两侧查找元素。因此,根据访问容器的方式,任何一方都可能是关键。当一侧是关键时,另一侧是价值。
  • Boost.Array 和 Boost.Unordered 定义了类 boost::array、boost::unordered_set 和 boost::unordered_map,它们是使用 C++11 添加到标准库中的。
  • Boost.CircularBuffer 提供了一个容器,其最重要的属性是当一个值被添加到一个完整的循环缓冲区时,它将覆盖缓冲区中的第一个元素。
  • Boost.Heap 提供了优先级队列的变体——类似于 std::priority_queue 的类。
  • Boost.Intrusive 允许您创建与标准库中的容器不同的容器,这些容器既不复制也不移动对象。但是,要将对象添加到侵入性列表中,对象的类型必须满足某些要求。
  • Boost.MultiArray 试图简化多维数组的使用。例如,可以将多维数组的一部分视为单独的数组。
  • Boost.Container 是一个库,它定义了与标准库相同的容器。例如,如果您需要在多个平台上支持一个程序,并且您希望避免由标准库中特定于实现的差异引起的问题,则使用 Boost.Container 是有意义的。

二、Boost.MultiIndex

Boost.MultiIndex 使得定义支持任意数量接口的容器成为可能。虽然 std::vector 提供了一个支持直接访问具有索引的元素的接口,而 std::set 提供了一个对元素进行排序的接口,但 Boost.MultiIndex 允许您定义支持这两个接口的容器。这样的容器可用于使用索引并以排序方式访问元素。

如果元素需要以不同的方式访问并且通常需要存储在多个容器中,则可以使用 Boost.MultiIndex。不必将元素同时存储在向量和集合中,然后连续同步容器,您可以使用 Boost.MultiIndex 定义一个容器,该容器提供向量接口和集合接口。

如果您需要访问基于多个不同属性的元素,Boost.MultiIndex 也很有意义。在示例 12.1 中,通过名称和腿数查找动物。如果没有 Boost.MultiIndex,则需要两个散列容器——一个按名称查找动物,另一个按腿数查找它们。

示例 12.1。使用 boost::multi_index::multi_index_container

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <string>
#include <iOStream>
using namespace boost::multi_index;
struct animal
{
  std::string name;
  int legs;
};
typedef multi_index_container<
  animal,
  indexed_by<
    hashed_non_unique<
      member<
        animal, std::string, &animal::name
      >
    >,
    hashed_non_unique<
      member<
        animal, int, &animal::legs
      >
    >
  >
> animal_multi;
int main()
{
  animal_multi animals;
  animals.insert({"cat", 4});
  animals.insert({"shark", 0});
  animals.insert({"spider", 8});
  std::cout << animals.count("cat") << '\n';
  const animal_multi::nth_index<1>::type &legs_index = animals.get<1>();
  std::cout << legs_index.count(8) << '\n';
}

​​​ 使用 Boost.MultiIndex 时,第一步是定义一个新容器。你必须决定你的新容器应该支持哪些接口以及它应该访问哪些元素属性。 在 boost/multi_index_container.hpp 中定义的类 boost::multi_index::multi_index_container 用于每个容器定义。这是一个至少需要两个参数的类模板。第一个参数是容器应存储的元素类型——在示例 12.1 中,这是一个名为动物的用户定义类。第二个参数用于表示容器应提供的不同索引。 基于 Boost.MultiIndex 的容器的主要优势在于您可以通过不同的接口访问元素。定义新容器时,可以指定接口的数量和类型。示例 12.1 中的容器需要支持按名称或腿数搜索动物,因此定义了两个接口。 Boost.MultiIndex 调用这些接口索引——这就是库名称的来源。

接口是在类 boost::multi_index::indexed_by 的帮助下定义的。每个接口都作为模板参数传递。示例 12.1 中使用了 boost::multi_index::hashed_non_unique 类型的两个接口,在 boost/multi_index/hashed_index.hpp 中定义。使用这些接口使容器的行为类似于 std::unordered_set 并使用哈希值查找值。

类 boost::multi_index::hashed_non_unique 也是一个模板,它的唯一参数是计算哈希值的类。因为容器的两个接口都需要查找动物,一个接口计算名称的哈希值,而另一个接口计算腿数。

Boost.MultiIndex 提供了在 boost/multi_index/member.hpp 中定义的帮助类模板 boost::multi_index::member 来访问成员变量。如示例 12.1 所示,已指定几个参数以让 boost::multi_index::member 知道应该访问动物的哪个成员变量以及成员变量的类型。

​​​ 尽管animal_multi 的定义起初看起来很复杂,但该类的工作方式就像一张地图。动物的名字和腿数可以看作是一个键/值对。容器animal_multi 优于std::unordered_map 之类的地图的优点是可以通过名称或腿数查找动物。 animal_multi 支持两种接口,一种基于名称,一种基于腿数。接口确定哪个成员变量是键,哪个成员变量是值。

要访问 MultiIndex 容器,您需要选择一个接口。如果您使用 insert() 或 count() 直接访问对象动物,则使用第一个接口。在示例 12.1 中,这是成员变量名称的哈希容器。如果您需要不同的界面,则必须明确选择它。

接口连续编号,从第一个接口的索引 0 开始。要访问第二个接口(如示例 12.1 所示),请调用成员函数 get() 并将所需接口的索引作为模板参数传入。 ​​​

get() 的返回值看起来很复杂。它访问一个名为 nth_index 的 MultiIndex 容器类,它又是一个模板。要使用的接口的索引必须指定为模板参数。该索引必须与传递给 get() 的索引相同。最后一步是访问名为 type of nth_index 的类型定义。 type 的值表示对应接口的类型。以下示例使用关键字 auto 来简化代码。

尽管您不需要知道接口的细节,因为它们是自动从 nth_index 和 type 派生的,您仍然应该了解访问的是哪种接口。由于接口在容器定义中是连续编号的,因此可以很容易地回答这个问题,因为索引同时传递给 get() 和 nth_index。因此,legs_index 是一个通过腿查找动物的哈希接口。

因为名字、腿等数据可以作为MultiIndex容器的key,所以不能随意改变。如果在通过名称查找动物后腿的数量发生了变化,则使用腿作为键的接口将不知道这种变化,也不知道需要计算新的哈希值。

就像 std::unordered_map 类型的容器中的键无法修改一样,存储在 MultiIndex 容器中的数据也无法修改。严格来说,存储在 MultiIndex 容器中的所有数据都是常量。这包括不被任何接口使用的成员变量。即使没有接口访问腿,腿也不能改变。

为了避免必须从 MultiIndex 容器中删除元素并插入新元素,Boost.MultiIndex 提供了成员函数来直接更改值。因为这些成员函数是在MultiIndex容器本身上操作的,并且因为容器中的元素没有被直接修改,所以所有的接口都会得到通知,可以计算出新的hash值。

示例 12.2。使用 modify() 更改 MultiIndex 容器中的元素

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <string>
#include <iostream>
using namespace boost::multi_index;
struct animal
{
  std::string name;
  int legs;
};
typedef multi_index_container<
  animal,
  indexed_by<
    hashed_non_unique<
      member<
        animal, std::string, &animal::name
      >
    >,
    hashed_non_unique<
      member<
        animal, int, &animal::legs
      >
    >
  >
> animal_multi;
int main()
{
  animal_multi animals;
  animals.insert({"cat", 4});
  animals.insert({"shark", 0});
  animals.insert({"spider", 8});
  auto &legs_index = animals.get<1>();
  auto it = legs_index.find(4);
  legs_index.modify(it, [](animal &a){ a.name = "dog"; });
  std::cout << animals.count("dog") << '\n';
}

Boost.MultiIndex 提供的每个接口都提供了成员函数 modify(),它直接在容器上运行。要修改的对象是通过作为第一个参数传递给 modify() 的迭代器来标识的。第二个参数是一个函数或函数对象,它的唯一参数是存储在容器中的类型的对象。函数或函数对象可以随心所欲地改变元素。示例 12.2 说明了如何使用成员函数 modify() 来更改元素。

到目前为止,只引入了一个接口:boost::multi_index::hashed_non_unique,它计算一个不必唯一的哈希值。为了保证没有值被存储两次,请使用 boost::multi_index::hashed_unique。请注意,如果值不满足特定容器的所有接口的要求,则无法存储值。如果一个接口不允许您多次存储值,那么另一个接口是否允许它并不重要。

示例 12.3。具有 boost::multi_index::hashed_unique 的 MultiIndex 容器

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <string>
#include <iostream>
using namespace boost::multi_index;
struct animal
{
  std::string name;
  int legs;
};
typedef multi_index_container<
  animal,
  indexed_by<
    hashed_non_unique<
      member<
        animal, std::string, &animal::name
      >
    >,
    hashed_unique<
      member<
        animal, int, &animal::legs
      >
    >
  >
> animal_multi;
int main()
{
  animal_multi animals;
  animals.insert({"cat", 4});
  animals.insert({"shark", 0});
  animals.insert({"dog", 4});
  auto &legs_index = animals.get<1>();
  std::cout << legs_index.count(4) << '\n';
}

示例 12.3 中的容器使用 boost::multi_index::hashed_unique 作为第二个接口。这意味着不能将两条腿数相同的动物存储在容器中,因为哈希值相同。

该示例尝试存储与已存储的猫具有相同腿数的狗。因为这违反了第二个接口具有唯一哈希值的要求,所以狗不会被存储在容器中。因此,当搜索有四只腿的动物时,程序会显示 1,因为只有猫被存储和计数。

示例 12.4。接口排序、ordered_non_unique 和 random_access

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/member.hpp>
#include <string>
#include <iostream>
using namespace boost::multi_index;
struct animal
{
  std::string name;
  int legs;
};
typedef multi_index_container<
  animal,
  indexed_by<
    sequenced<>,
    ordered_non_unique<
      member<
        animal, int, &animal::legs
      >
    >,
    random_access<>
  >
> animal_multi;
int main()
{
  animal_multi animals;
  animals.push_back({"cat", 4});
  animals.push_back({"shark", 0});
  animals.push_back({"spider", 8});
  auto &legs_index = animals.get<1>();
  auto it = legs_index.lower_bound(4);
  auto end = legs_index.upper_bound(8);
  for (; it != end; ++it)
    std::cout << it->name << '\n';
  const auto &rand_index = animals.get<2>();
  std::cout << rand_index[0].name << '\n';
}

Example12.4

示例 12.3 中的容器使用 boost:​

example2.4 介绍了 Boost.MultiIndex 的最后三个接口:boost::multi_index::sequenced、boost::multi_index::ordered_non_unique 和 boost::multi_index::random_access。

接口 boost::multi_index::sequenced 允许您将 MultiIndex 容器视为类型为 std::list 的列表。元素按给定的顺序存储。

使用 boost::multi_index::ordered_non_unique 接口,对象会自动排序。此接口要求您在定义容器时指定排序标准。示例 12.4 使用辅助类 boost::multi_index::member 按腿数对动物类型的对象进行排序。

boost::multi_index::ordered_non_unique 提供了特殊的成员函数来查找排序值中的特定范围。程序使用lower_bound() 和upper_bound() 搜索至少有4 条但不超过8 条腿的动物。因为它们需要对元素进行排序,所以其他接口不提供这些成员函数。

最后引入的接口是 boost::multi_index::random_access,它允许您将 MultiIndex 容器视为 std::vector 类型的向量。两个最突出的成员函数是 operator[] 和 at()。

boost::multi_index::random_access 包括 boost::multi_index::sequenced。使用 boost::multi_index::random_access,boost::multi_index::sequenced 的所有成员函数也都可用。

现在我们已经介绍了 Boost.MultiIndex 的四个接口,本章的其余部分将重点介绍键提取器。已经引入了一个关键提取器:boost::multi_index::member,它在 boost/multi_index/member.hpp 中定义。这个帮助类被称为键提取器,因为它允许您指定类的哪个成员变量应该用作接口的键。

示例 12.5 引入了另外两个密钥提取器。

示例 12.5。密钥提取器身份和 const_mem_fun

​:multi_index::hashed_unique 作为第二个接口。这意味着不能将两条腿数相同的动物存储在容器中,因为哈希值相同。

该示例尝试存储与已存储的猫具有相同腿数的狗。因为这违反了第二个接口具有唯一哈希值的要求,所以狗不会被存储在容器中。因此,当搜索有四只腿的动物时,程序会显示 1,因为只有猫被存储和计数。

示例 12.4。接口排序、ordered_non_unique 和 random_access

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <string>
#include <utility>
#include <iostream>
using namespace boost::multi_index;
class animal
{
public:
  animal(std::string name, int legs) : name_{std::move(name)},
    legs_(legs) {}
  bool operator<(const animal &a) const { return legs_ < a.legs_; }
  const std::string &name() const { return name_; }
private:
  std::string name_;
  int legs_;
};
typedef multi_index_container<
  animal,
  indexed_by<
    ordered_unique<
      identity<animal>
    >,
    hashed_unique<
      const_mem_fun<
        animal, const std::string&, &animal::name
      >
    >
  >
> animal_multi;
int main()
{
  animal_multi animals;
  animals.emplace("cat", 4);
  animals.emplace("shark", 0);
  animals.emplace("spider", 8);
  std::cout << animals.begin()->name() << '\n';
  const auto &name_index = animals.get<1>();
  std::cout << name_index.count("shark") << '\n';
}

在 boost/multi_index/identity.hpp 中定义的键提取器 boost::multi_index::identity 使用存储在容器中的元素作为键。这要求动物类是可排序的,因为动物类型的对象将用作接口 boost::multi_index::ordered_unique 的键。在示例 12.5 中,这是通过重载的 operator< 实现的。

头文件 boost/multi_index/mem_fun.hpp 定义了两个键提取器——boost::multi_index::const_mem_fun 和 boost::multi_index::mem_fun——它们使用成员函数的返回值作为键。在示例 12.5 中,name() 的返回值就是以这种方式使用的。 boost::multi_index::const_mem_fun 用于常量成员函数,而 boost::multi_index::mem_fun 用于非常量成员函数。

Boost.MultiIndex 提供了另外两个键提取器:boost::multi_index::global_fun 和 boost::multi_index::composite_key。前者可用于独立或静态成员函数,后者允许您设计一个由其他几个密钥提取器组成的密钥提取器。

练习

使用 Boost.MultiIndex 定义类animals_container:

#include <string>
#include <vector>
#include <iostream>
struct animal
{
    std::string name;
    int legs;
    bool has_tail;
};
class animals_container
{
public:
    void add(animal a)
    {
        // TODO: Implement this member function.
    }
    const animal *find_by_name(const std::string &name) const
    {
        // TODO: Implement this member function.
        return nullptr;
    }
    std::vector<animal> find_by_legs(int from, int to) const
    {
        // TODO: Implement this member function.
        return {};
    }
    std::vector<animal> find_by_tail(bool has_tail) const
    {
        // TODO: Implement this member function.
        return {};
    }
};
int main()
{
    animals_container animals;
    animals.add({ "cat", 4, true });
    animals.add({ "ant", 6, false });
    animals.add({ "spider", 8, false });
    animals.add({ "shark", 0, false });
    const animal *a = animals.find_by_name("cat");
    if (a)
        std::cout << "cat has " << a->legs << " legs\n";
    auto animals_with_6_to_8_legs = animals.find_by_legs(6, 9);
    for (auto a : animals_with_6_to_8_legs)
        std::cout << a.name << " has " << a.legs << " legs\n";
    auto animals_without_tail = animals.find_by_tail(false);
    for (auto a : animals_without_tail)
        std::cout << a.name << " has no tail\n";
}

到此这篇关于C++ Boost MultiIndex使用详细介绍的文章就介绍到这了,更多相关C++ Boost MultiIndex内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++BoostMultiIndex使用详细介绍

本文链接: https://lsjlt.com/news/170995.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C++BoostMultiIndex使用详细介绍
    目录一、关于BOOST的容器二、Boost.MultiIndex练习一、关于BOOST的容器 容器是 C++ 中最有用的数据结构之一。标准库提供了许多容器,而 Boost 库提供的更...
    99+
    2022-11-13
    C++ Boost MultiIndex C++ MultiIndex
  • C++四种cast使用详细介绍
    目录一、static_cast1、基本数据类型转换2、指针和void指针的转换 3、父类和子类之间的转换二、dynamic_cast三、const_cast1、加上cons...
    99+
    2024-04-02
  • C++命名空间使用详细介绍
    目录1.前言2.定义3.using 指令4.using 声明5.嵌套的命名空间1.前言 在c++中,为了避免代码名称上所产生冲突,引入了命名空间这个东西。 命名空间相当于划分出一定的...
    99+
    2024-04-02
  • C++移动语义详细介绍使用
    目录1.移动构造函数2.右值引用3.std::move()将左值强制转换为右值引用4.拷贝语义和移动语义1.移动构造函数 移动语义就是使用移动构造函数来构造对象。 我们知道在类中如果...
    99+
    2023-01-28
    C++移动语义 C++移动语义用法
  • C++继承详细介绍
    在我们进行开发的时候,我们经常会遇到抽象出来的类之间具有继承关系。 举个简单的例子,比如我们在设计某游戏,当中需要定义Human也就是人这个类。每个人有名字,以及一定的血量,能够工作...
    99+
    2024-04-02
  • C++中cout的格式使用详细介绍
    1.cout和i/i++/++i的组合使用 i++ 和 ++i 是有着不同的含义,和 cout 组合使用也会得到不同的结果,下面给出一段代码: #include <iost...
    99+
    2024-04-02
  • C#属性的详细介绍
    这篇文章主要讲解了“C#属性的详细介绍”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C#属性的详细介绍”吧!C# 属性示例代码class TimePeriod  ...
    99+
    2023-06-17
  • C++模板超详细介绍
    目录1.前言2.函数模板3.类模板1.前言 模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。 模板是创建泛型类或函数的蓝图或公式。 通常有两种形式:函数模板和...
    99+
    2024-04-02
  • C++超详细介绍模板
    目录定义例子格式处理方法定义 函数模板不是一个实在的函数,编译器不能为其生成可执行代码。定义函数模板后只是一个对函数功能框架的描述,当它具体执行时,将根据传递的实际参数决定其功能。 ...
    99+
    2024-04-02
  • C++ 封装 DLL 供 C# 调用详细介绍
    目录1、VLC代码封装1.1 QT(C++)工程1.2static 声明 m_instance 优化效率1.3封装 DLL1.4应用程序的导出函数1.5 vlc 简单封装的具体实现2...
    99+
    2024-04-02
  • ReentrantLock介绍及使用(超详细)
    点击 Mr.绵羊的知识星球 解锁更多优质文章。 目录 一、介绍 1. 简介 2. 是什么类型的锁 3. 优点 4. 原理 5. 主要方法 6. 使用时注意事项 二、实际应用 1. 案例一 2. 案例二 一、介绍 1. 简介     ...
    99+
    2023-09-20
    java 开发语言
  • fastjson 使用方法详细介绍
    Fastjson介绍Fastjson是一个Java语言编写的JSON处理器。遵循http://json.org标准,为其官方网站收录的参考实现之一。功能qiang打,支持JDK的各种类型,包括基本的JavaBean、Collection、M...
    99+
    2023-05-30
    fastjson 使用
  • TypeScript泛型使用详细介绍
    目录1 什么是泛型2 泛型方法3 泛型类4 泛型接口1 什么是泛型 泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别...
    99+
    2022-11-13
    TypeScript泛型 TypeScript泛型使用方法
  • C语言指针详细介绍
    本篇内容主要讲解“C语言指针详细介绍”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C语言指针详细介绍”吧!指针对于C来说太重要。然而,想要全面理解指针,除了要对C语言有熟练的掌握外,还要有计算机...
    99+
    2023-06-15
  • C语言数组详细介绍
    目录什么是数组一维数组二维数组数组越界 数组名 结尾什么是数组 数组(Array)是一种用来存储同一种类型的集合,是一种有序的线性结构表。并且数组元素的地址是连续...
    99+
    2024-04-02
  • C++的类与C#的类详细介绍
    本篇内容介绍了“C++的类与C#的类详细介绍”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!许多编程人员学习C++总结经验为,有的觉得C++语...
    99+
    2023-06-17
  • Vuex详细介绍和使用方法
    目录一、什么是Vuex二、运行机制三、创建项目1、使用脚手架搭建Vue项目2、安装Vuex3、启动项目4、配置使用Vuex4.1、创建store文件夹4.2、配置全局使用store对...
    99+
    2024-04-02
  • Java中ArrayList的使用详细介绍
    目录1.ArrayList类1.1ArrayList类概述1.2ArrayList类常用方法1.2.1构造方法1.2.2成员方法1.2.3示例代码1.3ArrayList存储字符串并...
    99+
    2024-04-02
  • Python 内置logging 使用详细介绍
    目录logging 的主要作用logging 日志等级logging 的基础函数logging 的四大组件(类)logging 的配置logging 和 print 的区别主要参考资...
    99+
    2024-04-02
  • 详细介绍Github的使用方法
    随着互联网技术的不断发展,越来越多的开发者开始加入到开源项目中,Github作为目前全球最大的代码托管平台之一,也成为了开发者们分享、学习、合作的重要工具之一。然而,如何使用Github来进行代码管理、版本控制、协作开发等,还是很多新手开发...
    99+
    2023-10-22
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作