Using struct as KEY and VALUE for map. find() operation giving error
Solution 1
Your declaration of operator<
is off.
struct keyInfo
{
string Key1;
string Key2;
bool keyInfo::operator <(keyInfo &A) const
{ return ((this->Key1<A.Key1)&&(this->Key2<A.Key2)); }
};
... and for several reasons:
- It is an error to prefix the declaration with the class name within the class. You only should do so if you define it outside the class. Some compilers are laxist, but the Standard says you should not do this.
- The reason you cannot compile is that
operator<
should accept both its operands either as values (for simple things) or byconst&
. Here you forgot theconst
forA
. - The definition is incorrect, your
operator<
has its semantics off as the properties ofantisymmetry
is not respected. - It is recommended that binary operators be declared as free functions outside the class.
All in all, the correct declaration and definition are:
struct keyInfo {
std::string Key1;
std::string Key2;
};
inline bool operator<(keyInfo const& left, keyInfo const& right) {
if (left.Key1 < right.Key1) { return true; }
if (left.Key1 > right.Key1) { return false; }
return left.Key2 < right.Key2;
}
If you can use Boost, a "simple" way to implement this is:
inline bool operator<(keyInfo const& left, keyInfo const& right) {
return boost::tie(boost::cref(left.Key1) , boost::cref(left.Key2))
< boost::tie(boost::cref(right.Key1), boost::cref(right.Key2));
}
Solution 2
Change parameter to const keyInfo& A
:
bool keyInfo::operator <(const keyInfo &A) const // keyInfo:: is unrequired here
In std::map
the key is held as const T
so when the std::map
implementation invokes keyInfo.operator<()
it is passing a const keyInfo&
, which cannot be converted to a keyInfo&
.
N D Thokare
Updated on June 04, 2022Comments
-
N D Thokare almost 2 years
Code in c++:
#include <iostream> #include <map> #include <string> using namespace std; struct keyInfo { string Key1; string Key2; bool keyInfo::operator <(keyInfo &A) const { return ((this->Key1<A.Key1)&&(this->Key2<A.Key2)); } }; struct valueInfo { int value1; int value2; int value3; valueInfo(const int A,const int B,const int C) : value1(A),value2(B),value3(C) {} }; typedef std::map<keyInfo, valueInfo> MapTYPE; int main() { MapTYPE TMap; keyInfo K; K.Key1="main"; K.Key2="i"; valueInfo V(-2,-3322,9000); TMap.insert(MapTYPE::value_type(K,V)); MapTYPE::iterator It1=TMap.find(K); It1=TMap.find(K); if(It1!=TMap.end()) std::cout<<"Success(K): "<<It1->second.value2<<std::endl; keyInfo E; E.Key1="main"; E.Key2="j"; //TMap.insert(std::pair<keyInfo,valueInfo>(E,V)); MapTYPE::iterator It2=TMap.find(E); if (It2!=TMap.end()) std::cout<<"Success(E): "<<(It2->second).value3<<std::endl; cin.get(); return 0; }
When I compile this code it gave me the error:
error C2679: binary '<' : no operator found which takes a right-hand operand of type 'const keyInfo1' (or there is no acceptable conversion)
Please let me know where I'm going wrong? Any help is highly appreciated. Thanks.
I have tried to implement own operator and used in map<>, code looks as follows:
#include <iostream> #include <map> #include <string> using namespace std; struct keyInfo { string Key1; string Key2; /*bool keyInfo::operator()(keyInfo const& Left,keyInfo const& Right) const{ return ((Left.Key1<Right.Key1)&&(Left.Key2<Right.Key2)); }*/ }; struct LessComparer{ bool operator()(keyInfo const& Left,keyInfo const& Right) const{ return !(Left.Key1==Right.Key1 && Left.Key2==Right.Key2); } }; struct valueInfo { int value1; int value2; int value3; valueInfo(const int A,const int B,const int C) : value1(A),value2(B),value3(C) {} }; typedef std::map<keyInfo, valueInfo, LessComparer> MapTYPE; int main() { MapTYPE TMap; keyInfo K; K.Key1="main"; K.Key2="i"; valueInfo V(-2,-3322,9000); TMap.insert(MapTYPE::value_type(K,V)); MapTYPE::iterator It1=TMap.find(K); It1=TMap.find(K); if(It1!=TMap.end()) std::cout<<"Success(K): "<<It1->second.value2<<std::endl; keyInfo E; E.Key1="main"; E.Key2="j"; //TMap.insert(std::pair<keyInfo,valueInfo>(E,V)); MapTYPE::iterator It2=TMap.find(E); if (It2!=TMap.end()) std::cout<<"Success(E): "<<(It2->second).value3<<std::endl; cin.get(); return 0; }
Here I'm using operator() to return 0 iff both Key1 and Key2 of Left and Right are equal. I think this is the same way map::less works, I mean it return false only if equality condition is satisfied.
It works fine in first case i.e. TMap.find(K) where same key is found. But during call in second case i.e. TMap.find(E) it pops up an error saying:
"Debug assertion failed" Expression: Invalid operator <
-
Bo Persson about 12 yearsIn addition to making the parameter
const
, you should also consider if you really want to have both keys less than each other. What happens ifKey1
is equal toA.Key1
?
-
-
N D Thokare about 12 yearsI have changed parameter to const keyInfo& A , still the same occurs.
-
Matthieu M. about 12 years@EthanSteinberg: thanks, but I don't remember off the top of my head if the
boost:cref
call is necessary. I think you can get away without it withtie
... but just didn't want to take any chance here. -
N D Thokare about 12 yearsI have tried using own comparer. can you reply to link: Using Own Comparator
-
N D Thokare about 12 yearsI have tried using own comparer. can you reply to link: Using Own Comparator