I try to directly consume elements from a set, which i cannot get to work from the outside getting an error
binding reference of type ‘int&&’ to ‘std::remove_reference<const int&>::type’ {aka ‘const int’} discards qualifiers
Consuming from a vector works perfectly fine. I really do not understand where syntactic the difference would be between consuming from the set or the vector, as they work similar cocerning their iterators.
I can make a Workaround pops()
, however, I do not neccessarily see this as a intuitive solution.
#include <vector>
#include <set>
#include <iostream>
class A {
public:
std::vector<int> intv_{1,2,3};
std::set<int> ints_{1,2,3};
int pops() {
auto rslt = std::move(*ints_.begin());
ints_.erase(ints_.begin());
return rslt;
}
};
using namespace std;
void consume_int(bool dummy, int&& i) {
cout << i << endl;
}
using namespace std;
int main() {
A a;
consume_int(true, std::move( *(a.intv_.begin()) )); //OK!
a.intv_.erase(a.intv_.begin());
consume_int(true, std::move( *a.ints_.begin() )); //FAIL to compile
a.ints_.erase(a.ints_.begin());
consume_int(true, std::move(a.pops())); //Workaround OK!
return 0;
}
The point is: You are not allowed to change the objects within a set, as this would require to move their location within the set. This is why the iterator only returns a const
reference even for non-const std::set
!
Now r-value references are intended to be used to modify the object (moving the contents away – which would be such an illegal change of the set entry! – at that point the set cannot know that you are going to erase the entry anyway), and you cannot assign const references to, which would open doors to all such illegal modifications (of set members, objects in non-writable memory sections, etc).
Edit: Still you actually can move elements out of a std::set
, provided you have at least C++17 available, in this case you can profit from the extract
function:
int pops()
{
auto handle = ints_.extract(ints_.begin());
auto rslt = std::move(handle.value()); // for DEMONSTRATION purposes!
return rslt;
}
with the handle getting discarded on exiting the function – though, actually you don't need to explicitly move anything at all, you can simply write:
int pops()
{
auto handle = ints_.extract(ints_.begin());
return handle.value();
// or as a one-liner:
return ints_.extract(ints_.begin()).value();
}