views:

135

answers:

1

What would be the most elegant way too fix the following code:

#include <vector>
#include <map>
#include <set>
using namespace std;

typedef map< int, int > row_t;
typedef vector< row_t > board_t;
typedef row_t::iterator area_t;

bool operator< ( area_t const& a, area_t const& b ) {
    return( a->first < b->first );
};

int main( int argc, char* argv[] )
{
    int row_num;
    area_t it;

    set< pair< int, area_t > > queue;
    queue.insert( make_pair( row_num, it ) ); // does not compile
};

One way to fix it is moving the definition of less< to namespace std (I know, you are not supposed to do it.)

namespace std {
    bool operator< ( area_t const& a, area_t const& b ) {
        return( a->first < b->first );
    };
};

Another obvious solution is defining less than< for pair< int, area_t > but I'd like to avoid that and be able to define the operator only for the one element of the pair where it is not defined.

+3  A: 

Firstly, in your code you provide a comparison operator for map iterator type instead of set element type. This is a completely useless thing to do. std::set<> will not use some independent iterator comparator, and it doesn't matter where or how you declare it. std::set needs a comparator for actual set element type, which is std::pair< int, area_t > in your case.

Secondly, when you are implementing a comparator that implements some specific and/or fairly exotic comparison approach, it is better to use a named function or a function object instead of hijacking the operator < for that purpose. I'd say that the natural way to compare a std::pair object would be to use lexicographical comparison. Since your comparison is not lexicographical, taking over operator < might not be a good idea. Better implement a comparator class

typedef pair< int, area_t > Pair; // give it a more meaningful name

struct CompareFirstThroughSecond {
  bool operator ()(const Pair& p1, const Pair& p2) const { 
    return p1.second->first < p2.second->first;
  }
};

and use it with your container

std::set< Pair, CompareFirstThroughSecond > queue;  

(I hope I deciphered your intent from your original code correctly).

You can also implement the above operator () method as a template method, thus making it usable with all std::pair-based types with an iterator as a second member. It might not make mich sense though, since your comparison is "exotic" enough.

AndreyT
You seem to be missing that `std::pair` already implements `operator<`, and OP is wondering how to plug in a comparator for the second member (iterator).
UncleBens
@UncleBens: Oh, got it. You are right. Still, what I proposed should work. Also, trying to implement a comparator for iterator type through operator overloading is a risky endeavor since in general case iterator might happen to be implemented by a built-in type (for which operator overloading is not possible).
AndreyT
@UncleBens - that's an excellent way of putting it. I want to _plug-in_ an operator for the second element of the pair.@AndreyT - I would need to compare the ints from the pair first and - if they are equal - go on and compare `area_t` members of the pair. That would work.But that's precisely the solution I was trying to avoid -- `operator<` is already implemented for `std::pair` and for ints. I do not want to reinvent the wheel. (Plus that's an awful lot of typing.)
Koszalek Opalek
@Koszalek Opalek: OK, but still keep in mind that if it so happens that your iterator type is a built-in type, your code will fail to compile, since it is illegal to overload operators for built-in types.
AndreyT