Boost logo

Boost Users :

Subject: Re: [Boost-users] [lambda] Defining a predicate for std::find_if if the key to a std::map is std::pair
From: Anthony Foglia (AFoglia_at_[hidden])
Date: 2009-09-24 22:04:14


Ryan wrote:
> On Thu, Sep 24, 2009 at 12:01 PM, Nat Goodspeed <nat_at_[hidden]> wrote:
>
>> Yes, that's what I was thinking: migrate the int from the key to the
>> mapped_type.
>
>
> This would indeed make the insert easier at the cost of complicating the
> retrieval. By making the int part of the key the retrieval is trival
>
> m_VariableDestinations.find(std::make_pair(name, intValue));
>
> If I was to move the int out of the pair I found that it increased the
> difficulty quite a bit.

        I don't think it's that bad. The retrieval will be only slightly worse
with an extra ".second" you'd need to add to get the vector of classA.

> On Thu, Sep 24, 2009 at 11:38 AM, Anthony Foglia <AFoglia_at_[hidden]>wrote:
>
>> He can pass a custom less functor class as the third template parameter to
>> the map. Something like:
>>
>
> Is the advantave of using the custom functor over the lambda class the
> ability to use the insert function correctly? By using the functor the
> insert, that Nat recommended, would indeed only compare the name value and
> correctly return true or false regardless of the second parameter. Is this
> correct?

        Yes, but it also will only compare the string value and not the int
when using map::find as well. The only real difference comes down to
how you get the vector<classA> value and the intValue from the iter.

typedef map< pair<string,int>, vector<classA>, LessFirstOfPair > cMap1;
typedef map< string, pair<int,vector<classA> > > cMap2;

cMap1 map1;
cMap2 map2;

cMap1::iterator it1 = map1.find(make_pair(name,intValue));
cMap2::iterator it2 = map2.find(name);

        The int part of the "key" can be retrieved with
it1->first.second
it2->second.first

        And the vector<classA> can be retrieved with
it1->second
it2->second.second

        I guess one benefit is that by overriding the template parameter, using
std::find_if becomes a little simpler, because both the string and int
are in the same "area". I think you can get away with

find_if(map1.begin(), map1.end(),
         bind(&cMap1::value_type::first, _1)
            ==make_pair(givenName, intValue));

but I haven't used bind and lambda often enough to be more than 60%
certain I got that right. :-) Using map::find should be faster for big
containers, but you'll need to manually check the int of the map key.

it1 = map1.find(make_pair(name,intValue));
if ((it1 == map1.end()) || (it1->first.second != intValue)) {
    // not found
}

        Using merely the string as the key sounds safer to me, both because
it's easier to initially code, and it's easier to maintain. (Eventually
you or the next coder will forget that in cMap1 the int part of the key
is ignored.)
        I just kept the overloaded template parameter in my reply because that
was my first thought. While writing it I realized the simpler,
non-overengineered string-only key approach.

-- 
Anthony Foglia
Princeton Consultants
(609) 987-8787 x233

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net