Board index » cppbuilder » predicates, binary_function's, etc. Which is better?

predicates, binary_function's, etc. Which is better?


2005-04-23 12:42:49 PM
cppbuilder15
Please take a look at the following two implementations of finding an
element in a vector. Both implementations work beautifully. But what is
the difference between them? Why would you choose one method over the
other? Is one more efficient than the other? When would each be more
appropriate than the other?
Given:
struct TCommandDef
{
AnsiString Name;
// ... other members
};
std::vector< TCommandDef>CommandDefs;
----------------------------------------------------------------------------
---
Method 1:
struct NameMatches
{
private:
AnsiString Name;
public:
NameMatches( AnsiString AName ) : Name(AName) {}
bool operator()( TCommandDef &CommandDef ) const
{
return CommandDef.Name == Name;
}
};
std::vector< TCommandDef>::iterator where =
std::find_if( CommandDefs.begin(),
CommandDefs.end(),
NameMatches(AName) );
----------------------------------------------------------------------------
---
Method 2:
struct NameMatches : public std::binary_function<const TCommandDef, const
AnsiString, bool>
{
bool operator()( const TCommandDef& CommandDef, AnsiString Name ) const
{
return CommandDef.Name == Name;
}
};
std::vector< TCommandDef>::iterator where =
std::find_if( CommandDefs.begin(),
CommandDefs.end(),
bind2nd(NameMatches(), AName) );
----------------------------------------------------------------------------
---
Thanks,
- Dennis
 
 

Re:predicates, binary_function's, etc. Which is better?

Your comparing elements to a different type which adds a level of
unnecessary complexity. I would add a constructor with the explicit keyword
for creating a temporary searching object. Also an equality operator would
be necessary which compares the private member. This can be a non-member
and would have to be a friend to access the private member. You can then
search with a instruction like this:
std::vector< TCommandDef>::iterator where =
std::find_if( CommandDefs.begin(),
CommandDefs.end(),
std::bind2nd(std::equal_to<TCommandDef>(),
TCommandDef(AName) ) );
Fraser.
 

Re:predicates, binary_function's, etc. Which is better?

"Fraser Ross" <fraserATmembers.v21.co.unitedkingdom>wrote in message
Quote
Your comparing elements to a different type which adds a level of
unnecessary complexity. I would add a constructor with the explicit
keyword
for creating a temporary searching object. Also an equality operator
would
be necessary which compares the private member. This can be a non-member
and would have to be a friend to access the private member. You can then
search with a instruction like this:


std::vector< TCommandDef>::iterator where =
std::find_if( CommandDefs.begin(),
CommandDefs.end(),
std::bind2nd(std::equal_to<TCommandDef>(),
TCommandDef(AName) ) );
That's fine, except that the equality operator would only work for that one
data member...i.e. it would not be generic enough to use for with data
members, and it would not be possible (I don't think) to do different
searches on different data members. With the methods I showed in my
original post, the data member being compared can be changed quite easily
just by creating a new functor/predicate.
- Dennis
 

{smallsort}

Re:predicates, binary_function's, etc. Which is better?

"Dennis Jones" < XXXX@XXXXX.COM >wrote in message
...
Quote

That's fine, except that the equality operator would only work for that
one
data member...i.e. it would not be generic enough to use for with data
members, and it would not be possible (I don't think) to do different
searches on different data members. With the methods I showed in my
original post, the data member being compared can be changed quite easily
just by creating a new functor/predicate.
It looks like what you need is a multi-index container:
www.boost.org/libs/multi_index/doc/index.html
 

Re:predicates, binary_function's, etc. Which is better?

"J Alexander" < XXXX@XXXXX.COM >wrote in message
Quote
"Dennis Jones" < XXXX@XXXXX.COM >wrote in message
news:426c69fb$ XXXX@XXXXX.COM ...
...
>
>That's fine, except that the equality operator would only work for that
>one
>data member...i.e. it would not be generic enough to use for with data
>members, and it would not be possible (I don't think) to do different
>searches on different data members. With the methods I showed in my
>original post, the data member being compared can be changed quite
easily
>just by creating a new functor/predicate.

It looks like what you need is a multi-index container:
www.boost.org/libs/multi_index/doc/index.html
Thanks, but you and Fraser both seemed to have missed the point of my
original post. I was not asking for a solution to a problem, but rather an
explanation of the benefits and drawbacks of two different implementations
that achieve the same goal, and as I am sure (most) everyone here knows,
much of software development involves finding and selecting from several
available implementation methods. Choosing the one most appropriate to the
problem at hand requires an understanding of the advantages and
disadvantages of each possible solution.
Fraser offered a third possible implementation (indeed, there are probably
many worthwhile implementations) and my response to Fraser's post was
nothing more than an observation of a potential drawback to his suggestion.
Fraser's post actually adds to the complexity of the original post, because
instead of only needing to analyze two solutions, I now have three!
When I first needed a solution to my particular problem, I found the two
methods given in my original post. Not that either one is an optimal
solution, but they solve the problem nonetheless. Those two solutions are
typical of that which is found in an STL textbook or offered by users in the
comp.lang.c++ newsgroups.
With the third implementation offered by Fraser, I can see that it has a
possible advantage in performance over the other two, but it also has the
disadvantage in that it will not scale to multiple data members (if that
were necessary -- though it is not in my case).
I cannot comment on the appropriateness of a multi-index container because:
A) I've never used one before, and B) the Boost multi_index library is known
to be unusable on Borland compilers (which is what we are all using here,
right?) due to a (presumably) non-conformance with the C++ standard.
I would still like to see a response that addresses that original question!
- Dennis
 

Re:predicates, binary_function's, etc. Which is better?

Method 1:
struct NameMatches : std::unary_function<TCommandDef, bool>
{
private:
AnsiString const Name;
public:
NameMatches( AnsiString const& AName ) : Name(AName) {}
bool operator()( TCommandDef const& CommandDef ) const
{
return CommandDef.Name == Name;
}
};
There was some errors with method 1 that I've corrected.
Method 2:
struct NameMatches : public std::binary_function<TCommandDef, AnsiString,
bool>
{
bool operator()( TCommandDef const& CommandDef, AnsiString const& Name )
const
{
return CommandDef.Name == Name;
}
};
Method 2 needed some corrections as well. Method 1 has 1 less parameter
with the operator() function which is why I think it is preferable. It is
closer to the example I gave than method 2.
Fraser.