C++ boost多索引容器、范围变异算法和常量

C++ boost多索引容器、范围变异算法和常量,c++,algorithm,boost,boost-multi-index,boost-range,C++,Algorithm,Boost,Boost Multi Index,Boost Range,我使用的是boost multi_index_容器,它是通过equal_range查询的,并且使用range::join和boost::any_range函数返回的结果 any_range引用参数被定义为对类型的常量引用-必须是常量,因为多索引容器的性质,不太确定引用。示例: typedef boost::any_range<TestData, boost::random_access_traversal_tag, const TestDa

我使用的是boost multi_index_容器,它是通过equal_range查询的,并且使用range::join和boost::any_range函数返回的结果
any_range引用参数被定义为对类型的常量引用-必须是常量,因为多索引容器的性质,不太确定引用。示例:

typedef boost::any_range<TestData, boost::random_access_traversal_tag,
                         const TestData &, std::ptrdiff_t> TestRange;
typedef boost::any_range TestRange;
现在我需要的是使用变异范围算法,如boost::sort、unique等,由于范围内元素的常量,这些算法显然无法在范围内运行。
除了将元素复制到新容器中,还有其他解决方法吗

编辑1:
结构和话筒示例:

struct TestData {
  TestData()
      : m_strMem01("test"), m_intMem02(rand()),
        m_boolMem03(rand() < RAND_MAX / 2) {}
  std::string m_strMem01;
  int m_intMem02;
  bool m_boolMem03;
};

typedef boost::multi_index_container<
    TestData,
    bmi::indexed_by<
        bmi::random_access<bmi::tag<struct RndKey1>>,
        bmi::ordered_non_unique<
            bmi::tag<struct Key1>,
            bmi::composite_key<
                TestData,
                bmi::member<TestData, std::string, &TestData::m_strMem01>,
                bmi::member<TestData, bool, &TestData::m_boolMem03>>>,
        bmi::ordered_non_unique<
            bmi::tag<struct Key4>,
            bmi::composite_key<
                TestData,
                bmi::member<TestData, std::string, &TestData::m_strMem01>,
                bmi::member<TestData, bool, &TestData::m_intMem02>>>,
        bmi::ordered_non_unique<
            bmi::tag<struct Key2>,
            bmi::member<TestData, int, &TestData::m_intMem02>>,
        bmi::ordered_non_unique<
            bmi::tag<struct Key3>,
            bmi::member<TestData, bool, &TestData::m_boolMem03>>>>
    TestDataContainer;
struct TestData{
TestData()
:m_stremm01(“测试”),m_intMem02(rand()),
m_boolMem03(rand()>,
bmi::有序非唯一<
标签,
复合密钥<
测试数据,
bmi::成员,
bmi::成员>>,
bmi::有序非唯一<
标签,
bmi::成员>,
bmi::有序非唯一<
标签,
bmi::会员>>>
测试数据容器;

听起来好像你根本不想把数据放在多索引容器中。multi_索引容器(顾名思义)旨在存储不可变数据,同时针对该数据维护多个索引(或具有约束的视图)

如果希望能够更新数据,可以将数据的一部分设置为可更改的,但必须确保
可更改的部分不参与索引构造

如果您真正想做的是改变数据并生成新的索引,那么您有两个选项-删除并重新插入或(更好)不使用boost::multi_index

一种方法是使用向量并维护您自己的临时索引

例如,字符串向量中唯一项的索引(保持简单):

vector unique\u stable\u索引(常量向量和数据)
{
无结构\u ptr{
布尔运算符()(常量字符串*l,常量字符串*r)常量{
返回*l<*r;
}
};
矢量结果;
集看到;
用于(常数自动和s:数据){
如果(请参见。插入(&s)。秒)
结果:推回(&s);
}
返回结果;
}

好的,一旦你有了你的范围,你就真的无法对它进行排序或以某种方式重新排列,因为元素的顺序是由索引固定的——这是由元素的常量强制执行的索引的一个绝对基本的不变量,就像你会发现的那样,比如说
std::set
。您可以使用原始元素的指针或引用创建一个更轻量级的视图,而不是将其完全复制到外部容器中,以后可以根据需要对其进行操作。这是一个将视图构造为
std::vector
s of
std::reference_wrapper
s的示例,这些视图指向以下元素:

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/range/algorithm/sort.hpp>
#include <boost/range/join.hpp>
#include <functional>
#include <iostream>
#include <vector>

using namespace boost::multi_index;

struct X
{
  int x,y;
};

std::ostream& operator<<(std::ostream& os,const X& a)
{
  return os<<"{"<<a.x<<","<<a.y<<"}";
}

typedef multi_index_container<
  X,
  indexed_by<
    ordered_non_unique<member<X,int,&X::x>>
  >
> multi_t;

struct view:std::vector<std::reference_wrapper<const X>>
{
  using base=std::vector<std::reference_wrapper<const X>>;

  template<typename InputIterator>
  view(InputIterator first,InputIterator last):base(first,last){}

  template<typename InputIterator>
  view(const std::pair<InputIterator,InputIterator> p):base(p.first,p.second){}  
};

int main()
{
  multi_t m={{0,1},{0,0},{0,2},{1,3},{1,1},{2,0},{2,1}};

  view v1=m.equal_range(0); // elements with x==0
  view v2=m.equal_range(2); // elements with x==2
  auto v3=boost::range::join(v1,v2); // join them
  boost::range::sort(v3,[](const X& a,const X& b){return a.y<b.y;}); // sort them by y
  for(const auto& x:v3)std::cout<<x<<" "; // output
}

因此,也许我不够清楚,我确实希望数据是不变的,而ad hoc被认为是一种性能不如MIC的东西。回到常量,可变算法并不是真正根据类实例的内部不变性来改变数据,只是它们必须取消引用和赋值,这就是为什么它们是可变的,换句话说,数据保持“常量”,排序和生成唯一视图在逻辑上与创建新索引不明确-视图本身就是索引。您可以通过将引用(指针或迭代器)复制到容器中来避免复制,并提供自定义比较器以在比较之前执行解引用(如上所述)。如果多索引比维护单独的索引“更快”,我会感到惊讶——当然更方便,但在我看来,多索引只是满足了您的部分需求。我遗漏了什么?至于“更快”、“更慢”,请勾选此项——至于涵盖需求,有两个部分,infra,它保存数据并向业务逻辑用户提供“查询”数据。然后业务逻辑开发人员需要根据自己的需要操作数据,不幸的是,这些需要必须操作数据,比如过滤掉不需要的数据,这需要可变性。复制指针被认为是最后的手段——我们谈论的是100万个项目,我应该尽最大努力在数据操作上提供微秒级的延迟。我不知道您的数据有多大。如果数据量不大,那么在SMP环境中复制数据通常是最快的解决方案。另一种方法可能是在构建多索引容器时过滤数据。i、 e.不要构建容器然后对其进行过滤,而是在项目存储在容器中时进行过滤。这样就不需要任何东西的拷贝(从boost 1.57 AFAIR开始,数据可以
移动到多索引中)嗨,很高兴在这里见到你:)我知道常数,这在MIC文档中提到过,但我想保留我的投诉权:)。撇开玩笑不谈,我对reference_wrapper不太熟悉,我猜在引擎盖下面是一个指针容器?所以,正如我之前提到的,我总是有这个选项,但是每次创建一个包含1M指针的容器并不是我所寻找的最优雅和面向性能的解决方案,如果。。。在我最初的问题中,我提到了sort和unique,如果我向用户提供额外的索引呢?一旦用户知道如何对结果进行排序或唯一化(选项数量有限),他应该再次查询麦克风,并按照自己的方式对范围进行排序或唯一化(或两者兼而有之)。让我们
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/range/algorithm/sort.hpp>
#include <boost/range/join.hpp>
#include <functional>
#include <iostream>
#include <vector>

using namespace boost::multi_index;

struct X
{
  int x,y;
};

std::ostream& operator<<(std::ostream& os,const X& a)
{
  return os<<"{"<<a.x<<","<<a.y<<"}";
}

typedef multi_index_container<
  X,
  indexed_by<
    ordered_non_unique<member<X,int,&X::x>>
  >
> multi_t;

struct view:std::vector<std::reference_wrapper<const X>>
{
  using base=std::vector<std::reference_wrapper<const X>>;

  template<typename InputIterator>
  view(InputIterator first,InputIterator last):base(first,last){}

  template<typename InputIterator>
  view(const std::pair<InputIterator,InputIterator> p):base(p.first,p.second){}  
};

int main()
{
  multi_t m={{0,1},{0,0},{0,2},{1,3},{1,1},{2,0},{2,1}};

  view v1=m.equal_range(0); // elements with x==0
  view v2=m.equal_range(2); // elements with x==2
  auto v3=boost::range::join(v1,v2); // join them
  boost::range::sort(v3,[](const X& a,const X& b){return a.y<b.y;}); // sort them by y
  for(const auto& x:v3)std::cout<<x<<" "; // output
}
{0,0} {2,0} {0,1} {2,1} {0,2}