Как говорит комментатор, поскольку карты "синхронизированы", вы не можете ожидать редактирования значения одной стороны, потому что это - ключ другой стороны.
Документация есть очень похожий пример, который подчеркивает эти невозможности. см. мое выделение в «operator[]
и at()
в « Различия со стандартными картами »
Я склонен в пользу MultiIndex. Он имеет те же существенные ограничения / семантику, но, на мой вкус, в нем меньше сюрпризов, потому что он обрабатывает его явным образом. Обратной стороной, конечно же, является то, что вам придется указывать индексы вручную.
MultiIndex Demo
Live On Coliru
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <iostream>
#include <iomanip>
#include <string>
namespace bmi = boost::multi_index;
struct Entry {
std::string key;
int id;
};
using Map = bmi::multi_index_container<Entry,
bmi::indexed_by<
bmi::ordered_unique<bmi::tag<struct by_key>,
bmi::member<Entry, std::string, &Entry::key> >,
bmi::ordered_non_unique<bmi::tag<struct by_id>,
bmi::member<Entry, int, &Entry::id> >
> >;
void dump(std::string_view caption, Map const& bimap) {
std::cout << caption << ":";
for (auto& [key,id] : bimap) {
std::cout << " {" << std::quoted(key) << ", " << id << "}";
}
std::cout << "\n";
}
int main() {
Map bimap;
auto& left = bimap.get<by_key>();
auto& right = bimap.get<by_id>();
// insertions through any index, or just `bumap` which will be the first
// idex
right.insert(Entry { "foo", 11 });
right.insert(Entry { "bar", 22 });
right.insert(Entry { "qux", 33 });
assert(bimap.size() == 3);
auto [it, ok] = right.insert(Entry { "foo", 23 });
assert(!ok);
assert(bimap.size() == 3);
dump("Before", bimap);
// looking for a single match:
if (auto it = left.find("foo"); it != left.end()) {
// to add more relations just insert,
// to replace the one match found:
bool ok = left.replace(it, {"something else", it->id}); // okay
assert(ok);
assert(it->key == "something else");
ok = left.replace(it, {"foo", 22}); // id doesn't need to be unique
assert(ok);
assert(it->key == "foo");
ok = left.replace(it, {"bar", 77}); // whoops, duplicate
assert( ! ok);
assert(it->key == "foo"); // unchanged
assert(it->id == 22); // unchanged
}
dump("First edit", bimap);
// query multiple
for (auto [it,end] = right.equal_range(22); it != end; ++it) {
// to add more relations just insert,
// to operate on the match
bool ok = right.modify(it, [](Entry& match) {
match.key = "twenty-two: " + match.key;
});
assert(ok);
}
dump("Second edit", bimap);
}
Печать
Before: {"bar", 22} {"foo", 11} {"qux", 33}
First edit: {"bar", 22} {"foo", 22} {"qux", 33}
Second edit: {"qux", 33} {"twenty-two: bar", 22} {"twenty-two: foo", 22}
Примечания, заключение:
Как вы Можно видеть, что мультииндекс принимает идиомы replace
/ modify
. Обратите внимание, что modify
может быть более эффективным способом обновления, но менее "atomi c" (проверьте документацию, как он ведет себя при конфликте) .