MultiIndex容器——提供向量和集合访问



我有一个应用程序,首先生成一个std::vector<int>对象。然后,需要对这个被视为std::set<int>的对象执行一些操作,其中顺序无关紧要,重复不算数。

目前,我从std::vector<int>对象显式地构造了一个类型为std::set<int>的对象。示例如下:

#include <cstdio>
#include <set>
#include <vector>
void printset(std::set<int>& Set) {
printf("Printing Set Elements: ");
for (std::set<int>::iterator siter = Set.begin(); siter != Set.end(); ++siter) {
int val = *siter;
printf("%d ", val);
}
printf("n");
}
void printvec(std::vector<int>& Vec) {
printf("Printing Vec Elements: ");
for (size_t i = 0, szi = Vec.size(); i < szi; ++i) {
int val = Vec[i];
printf("%d ", val);
}
printf("n");
}
int main()
{
std::vector<int> VecInt{ 6, 6, 5, 5, 4, 4 };
std::set<int> SetInt(VecInt.begin(), VecInt.end());
printvec(VecInt);
printset(SetInt);
}

我正在试着看看我是否可以使用Boost.MultiIndex来达到这个目的。Boost.MultiIndex状态简介:

如果元素需要以不同的方式访问,并且通常需要存储在多个容器中,则可以使用

Boost.MultiIndex。您可以使用Boost.MultiIndex定义一个容器,该容器提供向量接口和集合接口,而不必将元素存储在向量和集合中,然后连续同步容器。

这正是我正在做的(使用多个容器,然后不断地从另一个容器创建一个(,而我想创建一次(多索引(容器,然后提供一个向量接口和一个集合接口。

通过查看各种示例,例如这里和这里,不清楚如何将这些示例修改为上面的代码示例。

理想情况下,我想在上面的代码示例中做以下操作:

MultiIndexContainer vec_set_container;
vec_set_container.push_back(6);//or anything equivalent for the MultiIndexContainer
vec_set_container.push_back(6);
vec_set_container.push_back(5);
vec_set_container.push_back(5);
vec_set_container.push_back(4);
vec_set_container.push_back(4);
printvec(vec_set_container.Some_Function_That_Exposes_Vector_Interface());
printset(vec_set_container.Some_Function_That_Exposes_Set_Interface());

如何使用Boost.MultiIndex实现这一点?

随机访问索引将与;矢量";界面

有序的唯一索引将与";设置";界面

但是,如果您有一个唯一的索引,这将防止插入重复项。所以,你会得到:

实时编译器资源管理器

#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index_container.hpp>
#include <fmt/ranges.h>
namespace bmi = boost::multi_index;
using Table = bmi::multi_index_container< //
int,
bmi::indexed_by<
bmi::random_access<bmi::tag<struct asVector>>,
bmi::ordered_unique<bmi::tag<struct asSet>, bmi::identity<int>>>>;
int main()
{
Table data{ 6, 6, 5, 5, 4, 4 };
fmt::print("As vec {}nAs set {}n", //
data.get<asVector>(),    //
data.get<asSet>());
}

打印

As vec {6, 5, 4}
As set {4, 5, 6}

现在,我认为;最好的";这样做可以使顺序索引不唯一(因此,模拟std::multiset而不是std::set(:实时编译器资源管理器

bmi::ordered_non_unique<bmi::tag<struct asSet>, bmi::identity<int>>

打印

As vec [6, 6, 5, 5, 4, 4]
As set {4, 4, 5, 5, 6, 6}

如果你想遍历独特的元素,使用测距适配器的成本最低:

  1. 使用Boost实时

    fmt::print("As vec {}nAs set {}n", //
    data.get<asVector>(),     //
    data.get<asSet>() | boost::adaptors::uniqued);
    
  2. 使用RangeV3实时

    fmt::print("As vec {}nAs set {}n", //
    data.get<asVector>(),     //
    data.get<asSet>() | ranges::views::unique);
    
  3. 使用标准范围;我不能让这个工作,但它真的应该像std::ranges::unique(data.get<asSet>())一样

所有打印

As vec {6, 6, 5, 5, 4, 4}
As set {4, 5, 6}

其他想法

如果您不需要随机访问,那么sequenced索引可能更适合您。注意,这个接口附带了方便的unique()sort()方法(就像std::list一样(。

评论更新

以下是对评论的综合回应:

实时编译器资源管理器

#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index_container.hpp>
#include <fmt/ranges.h>
#include <random>
namespace bmi = boost::multi_index;
template <typename T>
using ListSet = bmi::multi_index_container< //
T,
bmi::indexed_by<
bmi::sequenced<bmi::tag<struct byInsertion>>,                   //
bmi::ordered_unique<bmi::tag<struct Ordered>, bmi::identity<T>> //
>>;
int main()
{
ListSet<int> data;
std::mt19937 prng{99}; // "random" seed
for (std::uniform_int_distribution d(1, 10); data.size() < 5;) {
int el = d(prng);
if (auto [it, unique] = data.push_back(el); not unique) {
fmt::print("Element {} duplicates index #{}n", el,
std::distance(begin(data), it));
}
}
fmt::print("By insertion {}nOrdered {}n", data, data.get<Ordered>());
}

打印

Element 9 duplicates index #3
Element 8 duplicates index #1
By insertion [7, 8, 5, 9, 1]
Ordered {1, 5, 7, 8, 9}

最新更新