5

I have a std::set container whose elements are objects of the following class:

class LaneConnector {
public:

    const Lane* getLaneFrom() const {
        return From;
    }
    const Lane* getLaneTo() const {
        return To;
    }

private:

    Lane* From;
    Lane* To;
}

and my comparator function is as follows:

struct MyLaneConectorSorter {
  bool operator() (LaneConnector * c, LaneConnector * d)
  {
      Lane* a = const_cast<Lane*>(c->getLaneFrom());
      Lane* b = const_cast<Lane*>(d->getLaneFrom());
      return (a->getLaneID() < b->getLaneID());
  }
} myLaneConnectorSorter;

Now when I try to sort the elements in the set with:

//dont panic, the container just came through a const_iterator of a std::map :)
const std::set<LaneConnector*> & tempLC = (*it_cnn).second;
std::sort(tempLC.begin(), tempLC.end(), myLaneConnectorSorter);

I get a frenzy of errors starting with the following lines, Appreciate if you help me solve this problem. Thanks:

/usr/include/c++/4.6/bits/stl_algo.h: In function ‘void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter = std::_Rb_tree_const_iterator<LaneConnector*>, _Compare = {anonymous}::MyLaneConectorSorter]’:
/home/.../dev/Basic/shared/conf/simpleconf.cpp:1104:65:   instantiated from here
/usr/include/c++/4.6/bits/stl_algo.h:5368:4: error: no match for ‘operator-’ in ‘__last - __first’
/usr/include/c++/4.6/bits/stl_algo.h:5368:4: note: candidates are:
/usr/include/c++/4.6/bits/stl_iterator.h:321:5: note: template<class _Iterator> typename std::reverse_iterator::difference_type std::operator-(const std::reverse_iterator<_Iterator>&, const std::reverse_iterator<_Iterator>&)
/usr/include/c++/4.6/bits/stl_iterator.h:378:5: note: template<class _IteratorL, class _IteratorR> typename std::reverse_iterator<_IteratorL>::difference_type std::operator-(const std::reverse_iterator<_IteratorL>&, const std::reverse_iterator<_IteratorR>&)
/usr/include/c++/4.6/bits/stl_bvector.h:181:3: note: std::ptrdiff_t std::operator-(const std::_Bit_iterator_base&, const std::_Bit_iterator_base&)
/usr/include/c++/4.6/bits/stl_bvector.h:181:3: note:   no known conversion for argument 1 from ‘std::_Rb_tree_const_iterator<LaneConnector*>’ to ‘const std::_Bit_iterator_base&’
rahman
  • 4,820
  • 16
  • 52
  • 86

1 Answers1

10

First, you cannot sort an std::set. It is a sorted structure, sorting happens upon construction or insertion.

Second, you can construct an std::set with your own sorting functor, and you can avoid unnecessary const_casts by making it take const pointers:

struct MyLaneConectorSorter {
  bool operator() (const LaneConnector* lhs, const LaneConnector* rhs) const
  {
    // you may want to put some null pointer checks in here
    const Lane* a = lhs->getLaneFrom();
    const Lane* b = rhs->getLaneFrom();
    return a->getLaneID() < b->getLaneID();
  }
};

and instantiate the set like this:

std::set<LaneConnector*, MyLaneConectorSorter> s(MyLaneConectorSorter());

or, if you want to construct it from a different set, with a different ordering,

std::set<LaneConnector*> orig = ..... ;
....
std::set<LaneConnector*, MyLaneConectorSorter> s(orig.begin(), orig.end(), MyLaneConectorSorter());
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • 2
    I always find it easier/cleaner to just override `bool operator<(const LaneConnector & _rhs)` – Rollie Sep 25 '12 at 05:48
  • @Rollie Same here, but it might not be applicable in this situation (there could be other sensible less-than comparisons). – juanchopanza Sep 25 '12 at 05:49
  • @juanchopanza How do i insert elements into this new set? for the sake of testing, I am just iterating through the old set and insert into the new set(s.insert(tempLC.begin(), tempLC.end());). but I am getting: /home/vahid/SIMMOBILITY/MASTER/simmobility/dev/Basic/shared/conf/simpleconf.cpp:1106:6: error: request for member ‘insert’ in ‘{anonymous}::s’, which is of non-class type ‘std::set({anonymous}::MyLaneConectorSorter (*)())’ – rahman Sep 25 '12 at 05:59
  • @rahman you can use another one of the `std::set` constructors, see my last edit. – juanchopanza Sep 25 '12 at 06:05
  • @juanchopanza yep, very close. It just gives error for the assignment of a const to non-const in the operator(). It works with all const_cast mess. let me see if I can solve it, otherwise I will trouble you again in a moment. thanks – rahman Sep 25 '12 at 06:09
  • @rahman I had one small error in the functor, which I think I have fixed. But `Lane::getLaneID()` must be a const method. – juanchopanza Sep 25 '12 at 06:12
  • @juanchopanza just declaring s as const will solve the issue. i appreciate if you edit it for others. thanks alot – rahman Sep 25 '12 at 06:12
  • ok, there is a problem inserting in the new set. it inserts only one(instead of 14) shall I take this to another thread? – rahman Sep 25 '12 at 06:38
  • @juanchopanza I faced another issue. it size of the resulting set is always 1. I took this to a new thread. I will appreciate if you have a look at it. http://stackoverflow.com/questions/12577571/sort-stdset-using-operator-to-order-the-insertions – rahman Sep 25 '12 at 06:52
  • This cannot work. `MyLaneConectorSorter::operator()` takes two `const LaneConnector&`, but the set contains `LaneConnector*`. – Gorpik Sep 25 '12 at 07:07
  • @Gorpik yes, the 'orig' and 's' are both constant. sorry we didn't edit that yet. – rahman Sep 25 '12 at 07:17
  • @juanchopanza: But you cannot call methods that take references and pass them pointers. Besides, that `operator()` does not even compile. I'll be more than happy to remove my downvote when you fix it, of course. – Gorpik Sep 25 '12 at 07:22
  • 1
    @Gorpik thanks, fixed that. I had misread your first comment. – juanchopanza Sep 25 '12 at 07:29