In order to extract move-only elements from a set, the only possibility is to use the extract
method, which was added in C++17:
while (!s.empty())
v.emplace_back(std::move(s.extract(s.begin()).value()));
If you cannot use C++17, it is permissible to modify an element of a set (e.g. using mutable
) only if you ensure that it retains the same position in the imposed ordering - that is, as long as it has the same result under your comparator when compared to all other members of the set. You can do this by providing a comparator that orders empty unique pointers before non-empty (note that the standard does not guarantee this) and erasing the modified element immediately after modifying it:
template<class T> struct MutableWrapper { mutable T value; };
template<class T> struct MutableWrapperCompare {
bool operator()(MutableWrapper<T> const& lhs, MutableWrapper<T> const& rhs) {
return lhs.value && rhs.value ? lhs.value < rhs.value : rhs.value;
}
};
int main()
{
std::set<MutableWrapper<std::unique_ptr<const C>>, MutableWrapperCompare<std::unique_ptr<const C>>> s;
std::vector<std::unique_ptr<const C>> v;
while (!s.empty())
{
v.emplace_back(std::move(s.begin()->value));
s.erase(s.begin());
}
}
This is however rather ugly and dangerous; you would be better off using boost::container::set
from Boost.Container, which has the C++17 extract method (since 1.62.0; it was undocumented, but this is just an oversight, note the corresponding extract
methods are documented for map
and multimap
).