1

I have:

struct foo {
    ...
    std::unique_ptr<Bar> bar; // requires foo to be move-only
    foo() { bar = std::make_unique<Bar>(); }
    foo(foo&&) = default;
};

typedef boost::multi_index_container<
    foo,
    boost::multi_index::indexed_by< 
        boost::multi_index::random_access<>,
        boost::multi_index::hashed_unique<
            boost::multi_index::composite_key<
                foo,
                boost::multi_index::member<X,std::string,&X::zoo>,
            >
        >
    >
> MyContainerType;

And two containers of this MyContainerType:

MyContainerType c1, c2;

And at some moment I want to iterate through all c1 elements and add some of them (according to some logics,) to c2. I tried:

for (auto it = c1.begin(); it != c1.end(); ++it) {
    if (...some logics... ) {
        c2.push_back(std::move(*it));
    }
}

But it does not compile, same as many another ways I have tried.

Textron
  • 21
  • 2

1 Answers1

0

You can use the trick outlined in that answer: Move element from boost multi_index array (which I linked you to on your previous question).

Live On Coliru

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/optional.hpp>
#include <iostream>

// move-only
struct foo {
    foo(int x) : x(x) {}
    foo(foo&&)      = default;
    foo(foo const&) = delete;
    foo& operator=(foo&&)      = default;
    foo& operator=(foo const&) = delete;

    int x;
};

template <typename Container>
void dump(std::ostream& os, Container const& c) { 
    for (auto& r: c) os << r.x << " ";
    os << "\n";
}

static_assert(not std::is_copy_constructible<foo>{}, "foo moveonly");

namespace bmi = boost::multi_index;

using foos = bmi::multi_index_container<foo, bmi::indexed_by<bmi::sequenced<> > >;

int main() {
    foos source, other;

    source.emplace_back(1);
    source.emplace_back(2);
    source.emplace_back(3);
    source.emplace_back(4);
    source.emplace_back(5);
    dump(std::cout << "Source before: ", source);

    for (auto it = source.begin(); it != source.end();) {
        if (it->x % 2) { // odd?
            boost::optional<foo> extracted;

            if (source.modify(it, [&](foo& v) { extracted = std::move(v); })) {
                it = source.erase(it);
            } else {
                ++it;
            }
            other.push_back(std::move(*extracted));
        } else {
            ++it;
        }
    }

    dump(std::cout << "Source after: ", source);
    dump(std::cout << "Other after: ", other);
}

This moves the odd items from source to other:

Source before: 1 2 3 4 5 
Source after: 2 4 
Other after: 1 3 5 
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Thanks! But can I add without erasing? There is no erasing mentioned in my question. And there is no obligatory erasing if I working with NOT move-only types... – Textron May 27 '18 at 00:09
  • You know. Remember when I asked for self-contained example? How will you be creating copies if **not** by moving? The type is _move-only_, right. – sehe May 27 '18 at 00:25
  • If you **do** want to move, but not erase the moved-from element, that is in principle not possible, due to the container invariants that might prevent it (see the [linked answer](https://stackoverflow.com/questions/46082394/move-element-from-boost-multi-index-array)). – sehe May 27 '18 at 00:26
  • Unfortunately I have a problem like: "passing const container* as this argument discards qualifiers", it's on "source.modify(it, ..." and "it = source.erase(it);", i.e. problem is what "it" is the const container*... And I am not using sequenced I using random_access+hashed_unique (tried to replace random_access to sequenced and same error appears) – Textron May 27 '18 at 04:53
  • That kind of message is pretty elementary C++. Just add your indices: [live](http://coliru.stacked-crooked.com/a/57f99900f9a55759). Now, your claim _"is what "it" is the const container*"_ seems confused. `it` is not the container. So all in all, you're running into (elementary) problems without stating the goal¹ so we can't help you see the _right_ solution. Until you post the **goal** with a **self-contained** piece of code that shows where you are stuck, this will likely keep happening. (¹ no, stating "it's not a simple merge is **not** a goal) – sehe May 27 '18 at 10:36