Re: std::multimap with composite key?
On Jan 19, 2:13 pm, PeteOlcott <PeteOlc...@gmail.com> wrote:
I want to make a std::multimap and use two std::string data members as
the key to the data record, is there a standard C++ way to do this?
struct NameValuePair
{
std::string Name;
std::string Value;
std::string ParentName;
std::string ParentValue;
};
You can store NameValuePair in std::set and use a custom less functor,
that only compares NameValuePair::Name and NameValuePair::Value to
establish strict weak ordering:
struct NameValuePair
{
std::string Name;
std::string Value;
std::string ParentName;
std::string ParentValue;
struct Less
{
bool operator()(NameValuePair const& a, NameValuePair const&
b) const
{
if(int r = a.Name.compare(b.Name))
return r < 0;
return a.Value.compare(a.Value) < 0;
}
};
};
typedef std::set<NameValuePair, NameValuePair::Less> NameValuePairSet;
The problem with the above approach is that because std::map::find()
requires a complete value for searching, i.e. you have to construct a
complete NameValuePair object, although you only search by
NameValuePair::Name and NameValuePair::Value members. Searching
NameValuePairSet looks like this:
NameValuePair const* find(
NameValuePairSet const& s
, std::string const& name
, std::string const& value
)
{
NameValuePair dummy_object_for_find = { name, value }; // <---
here
NameValuePairSet::const_iterator i = s.find
(dummy_object_for_find);
return i != s.end() ? &*i : NULL;
}
It may not always be convenient to construct dummy_object_for_find
just to satisfy std::set<> interface. And it is not elegant at all.
For better results I suggest you use boost::multi_index. This is how:
#include <string>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
struct NameValuePair
{
struct Key {
std::string Name;
std::string Value;
} key;
std::string ParentName;
std::string ParentValue;
struct LessKey
{
bool operator()(Key const& a, Key const& b) const
{
if(int r = a.Name.compare(b.Name))
return r < 0;
return a.Value.compare(a.Value) < 0;
}
};
struct ExtractKey
{
typedef Key result_type;
Key const& operator()(NameValuePair const& a) const
{
return a.key;
}
};
};
namespace M = boost::multi_index;
typedef M::multi_index_container<
NameValuePair
, M::indexed_by<
M::ordered_unique<NameValuePair::ExtractKey,
NameValuePair::LessKey>
>
NameValuePairSet;
NameValuePair const* find(
NameValuePairSet const& s
, std::string const& name
, std::string const& value
)
{
NameValuePair::Key key = { name, value };
NameValuePairSet::const_iterator i = s.find(key);
return i != s.end() ? &*i : NULL;
}
Please note that in this version of find only NameValuePair::Key
object is constructed.
See http://www.boost.org/doc/libs/1_37_0/libs/multi_index/doc/tutorial/inde=
x.html
for more details.
--
Max