Reputation: 1750
I'm trying to add multiple key-value pairs to a map having struct as both its key and value. Due to some reasons, only the first key-value pair that I add is being added to the map and the 2nd key-value pair couldn't be found.
#include<string>
#include<iostream>
#include<map>
using namespace std;
struct RJNodeAddress
{
string m_ip;
string m_port;
bool operator<(const RJNodeAddress &l)const
{
int l_size=l.m_ip.size();
int r_size=l.m_port.size();
return (l_size < r_size);
}
};
struct RJNodeDetails
{
string m_NodeType;
int m_appId;
};
class RJWebsocket
{
public:
static map<RJNodeAddress,RJNodeDetails> m_Nodes;
};
map<RJNodeAddress,RJNodeDetails> RJWebsocket::m_Nodes;
int main()
{
RJNodeAddress l_node1,l_node2;
RJNodeDetails l_add1,l_add2;
l_node1.m_ip="172.16.129.68";
l_node1.m_port="8766";
l_node2.m_ip="172.16.128.130";
l_node2.m_port="8768";
l_add1.m_appId=0;
l_add1.m_NodeType="CM";
l_add1.m_appId=1;
l_add1.m_NodeType="CM";
RJWebsocket::m_Nodes.insert({l_node1,l_add1});
RJWebsocket::m_Nodes.insert({l_node2,l_add2});
for(const auto& j:RJWebsocket::m_Nodes)
{
cout<<endl<<"Iterating through RJWebsocket::m_Nodes"<<endl;
cout<<endl<<"port: "<<j.first.m_port<<" "<<"IP: "<<j.first.m_ip<<endl;
}
}
The above code gives the following output:
Iterating through RJWebsocket::m_Nodes
port: 8766 IP: 172.16.129.68
Upvotes: 0
Views: 150
Reputation: 38267
Your comparison operator does something weird, I'd suggest relying on the one provided by std::tuple
like this:
#include <tuple>
bool operator<(const RJNodeAddress &l)const
{
return std::tie(m_ip, m_port) < std::tie(l.m_ip, l.m_port);
}
This way, the check for equivalence in std::map::insert
can correctly be performed and your snippet inside the main function indeed constructs two entries. The output on my machine then is
Iterating through RJWebsocket::m_Nodes
port: 8768 IP: 172.16.128.130
Iterating through RJWebsocket::m_Nodes
port: 8766 IP: 172.16.129.68
Note that as @DanielLangr pointed out in the comments, RJNodeAddress
could also directly be a type alias for std::pair<std::string, std::string>
or std::tuple<std::string, std::string>
, which provides a lexicographical operator <
out of the box and falls back to std::string::operator <
. This saves you from manually specifying the comparison, but has two drawbacks: it doesn't provide the expressiveness of naming the struct
and its data members, and its lexicographical comparison might not be what you intended in the first place.
Upvotes: 5
Reputation: 114705
Your operator<
is supposed to compare between two different RJNodeAddress
, you seem to be only looking at the operand (l
). Try something like this:
bool operator<(const RJNodeAddress &l)const
{
if (m_ip == l.m_ip)
return m_port < l.m_port;
return m_ip < l.m_ip;
}
Upvotes: 2
Reputation: 217275
Your operator doesn't respect compare requirement
bool operator<(const RJNodeAddress &l)const
{
int l_size=l.m_ip.size();
int r_size=l.m_port.size();
return (l_size < r_size); // Wrong
}
You probably want something like:
bool operator<(const RJNodeAddress &rhs)const
{
auto as_tuple = [](const RJNodeAddress & a){std::tie(a.m_ip, a.m_port); };
return as_tuple(*this) < as_tuple(rhs);
}
Upvotes: 2