Consider the following example code:
#include <map>
#include <vector>
int main() {
typedef std::pair<char, char> MyPair;
typedef std::multimap<char, char> MyMap;
typedef std::pair<MyMap::iterator, MyMap::iterator> MyRange;
std::vector<MyPair> pairs;
MyMap bigMapOfStuff;
//... adding things to pairs
auto pairsIter = pairs.begin();
MyRange range = bigMapOfStuff.equal_range('a');
//... range validation checking
MyPair pair = *range.first;
if(pair == *pairsIter) { //OK
//...
}
if(*pairsIter == *range.first) { //C2678
}
pair = *pairsIter;
if(*range.first == pair) { //C2678
//...
}
if(*range.first == *pairsIter) { //C2678
//...
}
if((MyPair)*range.first == *pairsIter) { //OK
//...
}
return 0;
}
In the comparisons I have commented //C2678 - this refers to the Visual Studio 2010 error:
error C2678: binary '==' : no operator found which takes a left-hand operand of type 'std::pair<_Ty1,_Ty2>' (or there is no acceptable conversion)
Why does this error occur in these cases?
I understand that pairsIter
is a std::vector<MyPair>::iterator
, and range.first
is a MyMap::iterator
, however, my expectation is that dereferencing the iterator returns the type, in this case std::pair<char, char>
for both iterators.
Why do I need to be explicit about it?
The reason is that std::multimap<char, char>::value_type
(which is also what dereferencing iterators gives you) is not std::pair<char, char>
. It's std::pair<const char, char>
. It's that way so that you can't modify the key of an item stored in the map, which could break the map's invariants.
If you assign (or cast) the result of the dereference to type std::pair<char, char>
, the comparison works. If you try to compare the different pair types directly, you get the error.
You could solve this by casting, or by providing your own function (either an overload of operator==
or a named function) for comparing the different types. Or, more generally, for comparing std:pair<T, U>
and std::pair<const T, U>
.