Проблема в том, что z
не является частью состояния объекта , только в контексте этого конкретного вида unordered_set
.
Если вы продолжите этот путь, то на всякий случай все будет изменяться.
В общем, то, что вы спрашиваете, невозможно, поскольку хеш элемента необходимо будет автоматически пересчитать при модификации элемента.
Самое общее, что вы можете сделать, это иметь протокол для модификации элемента, аналогичный функции modify
в Boost.MultiIndex https://www.boost.org/doc/libs/1_68_0/libs/multi_index/doc/reference/ord_indices.html#modify.
Код ужасен, но благодаря существованию extract
его можно сделать достаточно эффективным, когда это имеет значение (ну, тем не менее, ваша конкретная структура не получит выгоды от перемещения).
template<class UnorderedSet, class It, class F>
void modify(UnorderedSet& s, It it, F f){
It h = it; ++h;
auto val = std::move(s.extract(it).value());
f(val);
s.emplace_hint(h, std::move(val) );
}
int main(){
std::unordered_set<MyStruct, MyStructHash, MyStructEqual> set;
auto pair = set.emplace(100, 200);
if (pair.second) modify(set, pair.first, [](auto&& e){e.z = 300;});
std::cout << set.begin()->z;
}
(код не проверен)
@ JoaquinMLopezMuños (автор Boost.MultiIndex) предложил переустановить весь узел. Я думаю, что это будет работать так:
template<class UnorderedSet, class It, class F>
void modify(UnorderedSet& s, It it, F f){
It h = it; ++h;
auto node = s.extract(it);
f(node.value());
s.insert(h, std::move(node));
}
EDIT2 : окончательный проверенный код, требуется C ++ 17 (для извлечения)
#include <iostream>
#include <unordered_set>
struct MyStruct
{
int x, y;
double z;
MyStruct(int x, int y)
: x{ x }, y{ y }, z{ 0.0 }
{
}
};
struct MyStructHash
{
inline size_t operator()(MyStruct const &s) const
{
size_t ret = s.x;
ret *= 2654435761U;
return ret ^ s.y;
}
};
struct MyStructEqual
{
inline bool operator()(MyStruct const &s1, MyStruct const &s2) const
{
return s1.x == s2.x && s1.y == s2.y;
}
};
template<class UnorderedSet, class It, class F>
void modify(UnorderedSet& s, It it, F f){
auto node = s.extract(it++);
f(node.value());
s.insert(it, std::move(node));
}
int main(){
std::unordered_set<MyStruct, MyStructHash, MyStructEqual> set;
auto pair = set.emplace(100, 200);
if(pair.second) modify(set, pair.first, [](auto&& e){e.z = 300;});
std::cout << set.begin()->z;
}