Увеличить multi_index_container, алгоритмы изменения диапазона и постоянство

Я использую boost multi_index_container, который запрашивается равным equrange, а результат возвращается из функции с использованием range:: join и boost:: any_range
Аргумент any_range Reference определяется как const-ссылка на тип - должен быть const из-за природы multi_index_container, не совсем уверенной в ссылке. Пример:

typedef boost::any_range<TestData, boost::random_access_traversal_tag,
                         const TestData &, std::ptrdiff_t> TestRange;

Теперь мне нужно использовать алгоритмы мутирующего диапазона, такие как boost:: sort, unique и т. Д., Которые, очевидно, не могут работать в диапазоне из-за постоянства элементов в диапазоне.
Есть ли обходной путь, кроме копирования элементов в новый контейнер?

РЕДАКТИРОВАТЬ 1:
Пример struct и MIC:

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;

2 ответа

Решение

Хорошо, когда у вас есть свой диапазон, вы действительно не можете его отсортировать или каким-то образом переставить, потому что порядок элементов фиксируется индексом - это абсолютно фундаментальный инвариант индексов, поддерживаемый константностью элементов, так же, как вы найти с скажем std::set, Вместо того, чтобы делать полную копию во внешнем контейнере, вы можете создать более легкий вид из указателей или ссылок на исходные элементы, которыми впоследствии можно будет манипулировать по своему усмотрению. Это пример с представлениями, построенными как std::vectorс std::reference_wrapperс элементами:

Жить на Колиру

#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} 

Звучит так, как будто вы вообще не хотите, чтобы ваши данные были в контейнере multi_index. Контейнер multi_index (как и подсказки его имени) предназначен для хранения неизменяемых данных, сохраняя при этом несколько индексов (или представлений с ограничениями) для этих данных.

Вы можете сделать часть ваших данных mutable если вы хотите иметь возможность обновить его, но вы должны убедиться, что mutable части не участвуют в построении индекса.

Если вы действительно хотите изменить данные и получить новые индексы, то у вас есть 2 варианта - либо удалить и заново вставить, либо (что лучше) не использовать boost::multi_index.

Одним из подходов будет использование вектора и ведение собственных специальных индексов.

например, индекс уникальных записей в векторе строки (для простоты):

vector<const string*> unique_stable_index(const vector<string>& data)
{
    struct less_ptr {
        bool operator()(const string* l, const string* r) const {
            return *l < *r;
        }
    };

    vector<const string*> result;
    set<const string*, less_ptr> seen;
    for (const auto& s : data) {
        if(seen.insert(&s).second)
            result.push_back(&s);
    }

    return result;
}
Другие вопросы по тегам