
Hi Ion, thanks for your reply. Ion Gazta?aga wrote:
On 08/09/2019 14:21, Phil Endecott via Boost wrote:
Is it possible to make intrusive container elements movable?
It's true that there is no explicit operation to re-link a hook to the position the moved-from hook comes from. But you have the "swap_nodes" operation on the hook. In the move/copy constructor of your type you can default initialize the hook and then swap_nodes. In the move/copy assignment you can just "swap_nodes". Could this be useful in your vector use case?
Yes, that's exactly what is needed. Thanks for the hint! Here's a demo, just in case anyone else ever needs to do this. #include <boost/intrusive/set.hpp> #include <string> #include <vector> #include <algorithm> #include <iostream> #include <cassert> namespace bi = boost::intrusive; struct Thing { int id; std::string name; bi::set_member_hook<> name_hook; Thing() = default; Thing(int id_, std::string name_): id(id_), name(name_) {} Thing(const Thing& other) = delete; Thing(Thing&& other): id(other.id), name(std::move(other.name)), name_hook() { name_hook.swap_nodes(other.name_hook); } Thing& operator=(const Thing&) = delete; Thing& operator=(Thing&& other) { id = other.id; name = std::move(other.name); name_hook.swap_nodes(other.name_hook); return *this; } }; class Things { std::vector<Thing> data; struct name_compare_t { bool operator()(const Thing& a, const Thing& b) const { return a.name < b.name; } }; using thing_name_option = bi::member_hook< Thing, bi::set_member_hook<>, &Thing::name_hook >; using compare_name_option = bi::compare< name_compare_t >; // Can I use a lambda here? bi::set< Thing, thing_name_option, compare_name_option, bi::link_mode<bi::auto_unlink> > name_index; public: // Add, then sort, then lookup. void add(Thing&& t) { data.push_back(std::move(t)); name_index.insert(data.back()); } void sort() { std::sort(data.begin(), data.end(), [](auto& a, auto& b) { return a.id < b.id; }); } Thing& lookup_by_id(int id) { auto i = std::lower_bound(data.begin(), data.end(), id, [](auto& a, int b) { return a.id < b; }); assert( i != data.end() ); return *i; } Thing& lookup_by_name(std::string name) { Thing key{ 0, name }; // Can I avoid this? auto i = name_index.find(key); assert( i != name_index.end() ); return *i; } }; int main() { Things things; things.add({1, "Hello"}); things.add({2, "World"}); things.add({42, "Foo"}); things.add({420, "Blah"}); things.add({17, "Goodbye"}); things.sort(); auto& t1 = things.lookup_by_id(42); std::cout << t1.id << " = " << t1.name << "\n"; auto& t2 = things.lookup_by_id(17); std::cout << t2.id << " = " << t2.name << "\n"; auto& t3 = things.lookup_by_name("Hello"); std::cout << t3.name << " = " << t3.id << "\n"; auto& t4 = things.lookup_by_name("Blah"); std::cout << t4.name << " = " << t4.id << "\n"; }