views:

67

answers:

2

I have a nested set of ints but I cannot insert elements into the nested sets.

std::set<std::set<int> > centre_as_set = bitset_to_set(centre->second->bit_partitions);
std::set<std::set<int> >::iterator set_itr;
for ( set_itr = centre_as_set.begin(); set_itr != centre_as_set.end(); ++set_itr ) {
    set_itr->insert(4);
    std::set<int>::iterator node_itr;
    for ( node_itr = set_itr->begin(); node_itr != set_itr->end(); ++node_itr ) {
            std::cout << *node_itr;
        }
    }
}

The error is

Partition_standalone.cpp:612: error: passing ‘const std::set, std::allocator >’ as ‘this’ argument of ‘std::pair, _Compare, typename _Alloc::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::insert(const _Key&) [with _Key = int, _Compare = std::less, _Alloc = std::allocator]’ discards qualifiers

I can't quite decipher that template error, any help appreciated.

A: 

Edit: This answer is wrong as per the comment of georg.

I dont have a compiler here, but the full declaration of std::set is:

template < class Key, class Compare = less<Key>,
           class Allocator = allocator<Key> > class set;

The "Key" of the outermost set is "std::set". The Comparator is "std::less>", or short "operator<(set, set)" which is undefined. The compiler warns about this only on the first use/instantiation of the comparator.

I dont think there is a useful ordering/comparator for std::set's. You are better off using std::vector which doesnt order the elements and doesnt need a comparator.

Oh, and it is not allowed to change (at runtime) the set keys if this would affect the ordering. But that would be a runtime error, not a compile error.

Markus Kull
There is an `operator<`, see e.g. [here](http://www.cplusplus.com/reference/stl/set/operators/).
Georg Fritzsche
It's not a runtime error, it's a compile error and that is what his problem is.
SoapBox
Worth deleting your post if it's wrong?
chrispy
+5  A: 

The elements in a set are not mutable and you are trying to use the non-const member function insert() on a const instance of std::set<int>. There is the following nice comment if you follow the iterator symbol to its declaration in stl_set.h:

// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 103. set::iterator is required to be modifiable,
// but this allows modification of keys.
typedef typename _Rep_type::const_iterator iterator;

C++98 and C++03 allowed modification, but this is a defect and already fixed in non-ancient GCC versions and VC10. The mentioned defect report can be found here and will be incorporated into the next standard.

Use e.g. something like the following instead to add the value 4:

// Readability:
typedef std::set<int> IntSet;
typedef std::set<IntSet> IntSetSet;

// Helper:
IntSetSet add_value_to_sets(const IntSetSet& in, int i) {
    IntSetSet ss;
    IntSetSet::iterator set_itr;
    for ( set_itr = in.begin(); set_itr != in.end(); ++set_itr ) {
        IntSet s = *set_itr;
        s.insert(4);
        ss.insert(s);
    }
    return ss;
}

// ...
IntSetSet centre_as_set = 
    add_value_to_sets(bitset_to_set(centre->second->bit_partitions), 4);
Georg Fritzsche
Ow. I dont know if i like this glibcxx feature. This effectively prevents changing the set contents even if the change wouldnt have an effect on the ordering. E.g. changing attributes which are not compared.
Markus Kull
I'd say most of the use-cases where this is useful are better covered by associative containers like `std::map`. For me its definitely better than accidentally breaking everything at runtime.
Georg Fritzsche