Consider:
#include <stdio.h>
#include <set>
void printset(std::set<int>& Set) {
for (std::set<int>::iterator siter = Set.begin(); siter != Set.end(); siter) {
int val = *siter;
printf("%d ", val);
}
}
void printsetofset0(std::set<std::set<int>>& SetofSet) {
for (std::set<std::set<int>>::iterator siter = SetofSet.begin(); siter != SetofSet.end(); siter) {
std::set<int> Set = *siter;
printset(Set);
}
}
void printsetofset1(std::set<std::set<int>>& SetofSet) {
for (std::set<std::set<int>>::iterator siter = SetofSet.begin(); siter != SetofSet.end(); siter) {
printset(*siter);//this line gives error
}
}
printsetofset1
with the printset(*siter);
gives error:
<source>: In function 'void printsetofset1(std::set<std::set<int> >&)':
<source>:20:34: error: binding reference of type 'std::set<int>&' to 'const std::set<int>' discards qualifiers
20 | printset(*siter);
| ^~~~~~
<source>:4:38: note: initializing argument 1 of 'void printset(std::set<int>&)'
4 | void printset(std::set<int>& Set) {
| ~~~~~~~~~~~~~~~^~~
Compiler returned: 1
See Godbolt Link here.
printsetofset0
with the lines: std::set<int> Set = *siter; printset(Set);
compiles and works just fine.
What is the reason why one printsetofset0
works, while seemingly functionally equivalent (and shorter) preintsetofset1
does not work?
CodePudding user response:
The elements, which the iterator points to, are constant. You can read it here in the Notes: Because both iterator and const_iterator are constant iterators (and may in fact be the same type), it is not possible to mutate the elements of the container through an iterator returned by any of these member functions.. But, passing a reference to your printset
function would violate this property.
Internally, sets allow fast access via index structures. Changing the elements would require to reorder the set (internally).
You can solve the situation by adding a const
modifier to the parameter of your printset
function:
void printset(const std::set<int>& Set)
CodePudding user response:
All your print functions should take their argument by const reference, because they don't need to modify the argument. Like this:
void printset(const std::set<int>& Set)
I also suggest a range-based for loop to simplify your code:
for (int val : Set)
The reason printset
cannot take a non-const reference is that you're passing it the set-within-a-set, and the values stored in sets are always const. For more on this, see: Why does std::set seem to force the use of a const_iterator?
CodePudding user response:
The problem is that although the set types define both the iterator
and const_iterator
types, both types of iterators give us read-only access to the elements in the set. That is, the keys in a set are const
. We
can use a set iterator to read, but not write, an element’s value.
So to solve the error in your program you need to add a low-level const to the parameter named Set
of the printSet
function as shown below:
//------------vvvvv--------------------------->low-level const added here
void printset(const std::set<int>& Set) {
//other code as before
}