I'm using boost multi_index_container, which is queried by equal_range and the result returned from the function using range::join and boost::any_range
The any_range Reference argument is defined as const reference to the type - must be const because of the multi_index_container nature, not quite sure about the reference. Example:
typedef boost::any_range<TestData, boost::random_access_traversal_tag,
const TestData &, std::ptrdiff_t> TestRange;
Now what I need is to use mutating range algorithms like boost::sort, unique, etc., which obviously cannot run on range because of the constness of elements in range.
Is it any workaround except copying elements into new container?
EDIT 1:
struct and MIC example:
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;
OK, once you have your range you really can't sort it or somehow rearrange it because the order of elements is fixed by the index --this is an absolutely fundamental invariant of indices enforced by the constness of elements, much as you'd find with say a std::set
. Rather than doing a full copy to an external container you can create a more lightweight view out of pointers or references to the original elements that can later be manipulated as you wish. This is an example with views constructed as std::vector
s of std::reference_wrapper
s to the elements:
#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
}
Output:
{0,0} {2,0} {0,1} {2,1} {0,2}