By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
458,107 Members | 1,253 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 458,107 IT Pros & Developers. It's quick & easy.

Help with template find_if predicate

P: n/a
Hi there,

I found out that very often I use the following construct:

for (it = myvec.begin(); it != myvec.end(); ++it) {
if (it->name() == "myname")
break;
}

Certainly, the container the method and the constant can be of
any type.

The purpose is to have a template functor and use the
std::find_if instead of above loop.
I tried to mix something with std::mem_func and std::equal.
It looks that this is above my powers.

Thanks,

Mike.

Jul 22 '05 #1
Share this Question
Share on Google+
14 Replies


P: n/a
"mikets" <mi****@frontline-pcb.com> wrote in message
news:bt**********@news2.netvision.net.il...
Hi there,

I found out that very often I use the following construct:

for (it = myvec.begin(); it != myvec.end(); ++it) {
if (it->name() == "myname")
break;
}

Certainly, the container the method and the constant can be of
any type.

The purpose is to have a template functor and use the
std::find_if instead of above loop.
I tried to mix something with std::mem_func and std::equal.
It looks that this is above my powers.

Thanks,

Mike.


It's a little tricky because we must deal with various types which happen to
have a method called "name". But it can be done with templates:

template <typename NAMED>
class MatchName
{
private:
std::string
m_name;

public:
MatchName(const NAMED &i_named) : m_name(i_named.name()) {}

bool
operator () (const NAMED &other) const {return other.name() == m_name;}
};

template <typename ITER, typename NAMED>
ITER
find_by_name(ITER first, ITER last, const NAMED &target)
{
return std::find_if(first, last, MatchName<NAMED>(target));
}

You call it like this:

find_by_name(v.begin(), v.end(), Person("Melvin"))

where "Person" is a class with a method called "name".

--
Cy
http://home.rochester.rr.com/cyhome/
Jul 22 '05 #2

P: n/a
In article <bt**********@news2.netvision.net.il>,
mikets <mi****@frontline-pcb.com> wrote:
Hi there,

I found out that very often I use the following construct:

for (it = myvec.begin(); it != myvec.end(); ++it) {
if (it->name() == "myname")
break;
}

Certainly, the container the method and the constant can be of
any type.

The purpose is to have a template functor and use the
std::find_if instead of above loop.
I tried to mix something with std::mem_func and std::equal.
It looks that this is above my powers.


Here's one way to do it using std::tr1::bind:

std::vector<A>::iterator i =
std::find_if
(
myvec.begin(),
myvec.end(),
std::tr1::bind
(
std::equal_to<std::string>(),
std::tr1::bind
(
&A::name,
_1
),
"myname"
)
);

You can also find bind at www.boost.org.

-Howard
Jul 22 '05 #3

P: n/a
mikets wrote:
Hi there,

I found out that very often I use the following construct:

for (it = myvec.begin(); it != myvec.end(); ++it) {
if (it->name() == "myname")
break;
}

Certainly, the container the method and the constant can be of
any type.

The purpose is to have a template functor and use the
std::find_if instead of above loop.
I tried to mix something with std::mem_func and std::equal.
It looks that this is above my powers.

Here is a candidate predicate:
template < class T,
class ConstType,
const ConstType (T::*method)() >
class EqualThruMemFunc {
public:
EqualThruMemFunc( const ConstType& value ) :
mValue( value ) { }
bool operator()( T& instance ) {
return (instance.*method)() == mValue ;
}
private:
const ConstType& mValue ;
} ;

class Foo {
public
// ...
const std::string name() ;
} ;

// ...

typedef vector<Foo> MyVecType ;
//
MyVecType myvec ;

MyVecType::iterator it =
find_if( myvec.begin(),
myvec.end(),
EqualThruMemFunc<MyVecType,
std::string,
&MyVecType::name>("myname") ) ;
I am sure there is a more elegant solution for a general case. But this
should get you started.

Later,
--
CrayzeeWulf
Jul 22 '05 #4

P: n/a
Howard Hinnant wrote:
Here's one way to do it using std::tr1::bind:


What is std::tr1?

Jul 22 '05 #5

P: n/a
Daniel T. wrote:
mikets <mi****@frontline-pcb.com> wrote:

Hi there,

I found out that very often I use the following construct:

for (it = myvec.begin(); it != myvec.end(); ++it) {
if (it->name() == "myname")
break;
}

Certainly, the container the method and the constant can be of
any type.

The purpose is to have a template functor and use the
std::find_if instead of above loop.
I tried to mix something with std::mem_func and std::equal.
It looks that this is above my powers.

it = find_if(myvec.begin(), myvec.end(),
compose1(bind2nd(equal_to<string>(), "myname"),
mem_fun_ref(&foo::name)));

Note: the above uses the non-standard, but obviously very useful,
unary_compose adaptor. An implementation of which can be found on SGI's
website.

Here is a complete program proving that the above find_if is equivalent
to your origional loop:

/*
* Portions Copyright (c) 1994 Hewlett-Packard Company
* used with permission.
*/
#include <string>
#include <iostream>
#include <vector>
#include <functional>

class foo {
std::string _name;
public:
foo( const std::string& n ): _name( n ) { }
const std::string& name() const { return _name; }
};

template <class _Operation1, class _Operation2>
class unary_compose
: public std::unary_function<typename _Operation2::argument_type,
typename _Operation1::result_type>
{
protected:
_Operation1 _M_fn1;
_Operation2 _M_fn2;
public:
unary_compose(const _Operation1& __x, const _Operation2& __y)
: _M_fn1(__x), _M_fn2(__y) {}
typename _Operation1::result_type
operator()(const typename _Operation2::argument_type& __x) const {
return _M_fn1(_M_fn2(__x));
}
};

template <class _Operation1, class _Operation2>
inline unary_compose<_Operation1,_Operation2>
compose1(const _Operation1& __fn1, const _Operation2& __fn2)
{
return unary_compose<_Operation1,_Operation2>(__fn1, __fn2);
}

int main()
{
using namespace std;
vector<foo> myvec;
myvec.push_back( foo( "joe" ) );
myvec.push_back( foo( "myname" ) );
myvec.push_back( foo( "harold" ) );

vector<foo>::iterator it;
for (it = myvec.begin(); it != myvec.end(); ++it) {
if (it->name() == "myname")
break;
}
assert( it->name() == "myname" );

vector< foo >::iterator it2 = find_if( myvec.begin(), myvec.end(),
compose1( bind2nd( equal_to<string>(), "myname" ),
mem_fun_ref(&foo::name) ) );
assert( it2 == it );

cout << "OK" << endl;
}


I've been looking for something along those lines. :)

Jul 22 '05 #6

P: n/a

"Jeff Schwab" <je******@comcast.net> wrote in message
news:4s********************@comcast.com...
| Daniel T. wrote:
| > mikets <mi****@frontline-pcb.com> wrote:

[snip]

| > int main()
| > {
| > using namespace std;
| > vector<foo> myvec;
| > myvec.push_back( foo( "joe" ) );
| > myvec.push_back( foo( "myname" ) );
| > myvec.push_back( foo( "harold" ) );
| >
| > vector<foo>::iterator it;
| > for (it = myvec.begin(); it != myvec.end(); ++it) {
| > if (it->name() == "myname")
| > break;
| > }
| > assert( it->name() == "myname" );
| >
| > vector< foo >::iterator it2 = find_if( myvec.begin(), myvec.end(),
| > compose1( bind2nd( equal_to<string>(), "myname" ),
| > mem_fun_ref(&foo::name) ) );
| > assert( it2 == it );
| >
| > cout << "OK" << endl;
| > }
|
| I've been looking for something along those lines. :)

Yeah, but it requires another header, more work, and
besides, it's ugly :-).

Here is another example(I haven't tested it
much), that I came up with:

# include <iostream>
# include <ostream>
# include <string>
# include <vector>

class Person
{
private:
std::string Name;
public:
Person( const std::string& n ) : Name( n ) {}
std::string name() const { return Name; }
};

template<class Object, class DataType> class MatchName
{
private:
DataType ToFind;
DataType (Object::* PMF)();
public:
template<class PtrToFunc>
MatchName( const DataType& Arg, PtrToFunc (Object::* Ptr)() const )
: ToFind( Arg ), PMF( Ptr ) {}

bool operator() ( Object& Element ) const
{
return ToFind == ( Element.*PMF )();
}

// Example overload for std::vector<Person*>
bool operator() (Object*& Element) const
{
return ToFind == (Element ->* PMF)();
}
};

int main()
{
std::vector<Person> V;
V.push_back( Person( "Chris" ) );

if( std::find_if( V.begin(), V.end(),
MatchName<Person, std::string>( "Chris", &Person::name ) ) != V.end() )
std::cout << "Working with Chris :-) " << std::endl;

return 0;
}

What do you think ? Comments ?

Cheers.
Chris Val
Jul 22 '05 #7

P: n/a
On Mon, 05 Jan 2004 12:19:35 +0100, Rolf Magnus <ra******@t-online.de>
wrote:
Howard Hinnant wrote:
Here's one way to do it using std::tr1::bind:


What is std::tr1?


See section 1.3 of:
http://std.dkuug.dk/jtc1/sc22/wg21/d...2003/n1540.pdf

Tom

C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Jul 22 '05 #8

P: n/a
"Chris ( Val )" <ch******@bigpond.com.au> wrote in message
news:bt************@ID-110726.news.uni-berlin.de...

"Jeff Schwab" <je******@comcast.net> wrote in message
news:4s********************@comcast.com...
| Daniel T. wrote:
| > mikets <mi****@frontline-pcb.com> wrote:

[snip]

| > int main()
| > {
| > using namespace std;
| > vector<foo> myvec;
| > myvec.push_back( foo( "joe" ) );
| > myvec.push_back( foo( "myname" ) );
| > myvec.push_back( foo( "harold" ) );
| >
| > vector<foo>::iterator it;
| > for (it = myvec.begin(); it != myvec.end(); ++it) {
| > if (it->name() == "myname")
| > break;
| > }
| > assert( it->name() == "myname" );
| >
| > vector< foo >::iterator it2 = find_if( myvec.begin(), myvec.end(),
| > compose1( bind2nd( equal_to<string>(), "myname" ),
| > mem_fun_ref(&foo::name) ) );
| > assert( it2 == it );
| >
| > cout << "OK" << endl;
| > }
|
| I've been looking for something along those lines. :)

Yeah, but it requires another header, more work, and
besides, it's ugly :-).

Here is another example(I haven't tested it
much), that I came up with:

# include <iostream>
# include <ostream>
# include <string>
# include <vector>

class Person
{
private:
std::string Name;
public:
Person( const std::string& n ) : Name( n ) {}
std::string name() const { return Name; }
};

template<class Object, class DataType> class MatchName
{
private:
DataType ToFind;
DataType (Object::* PMF)();
public:
template<class PtrToFunc>
MatchName( const DataType& Arg, PtrToFunc (Object::* Ptr)() const )
: ToFind( Arg ), PMF( Ptr ) {}

bool operator() ( Object& Element ) const
{
return ToFind == ( Element.*PMF )();
}

// Example overload for std::vector<Person*>
bool operator() (Object*& Element) const
{
return ToFind == (Element ->* PMF)();
}
};

int main()
{
std::vector<Person> V;
V.push_back( Person( "Chris" ) );

if( std::find_if( V.begin(), V.end(),
MatchName<Person, std::string>( "Chris", &Person::name ) ) != V.end() ) std::cout << "Working with Chris :-) " << std::endl;

return 0;
}

What do you think ? Comments ?

Cheers.
Chris Val


Here's the code the OP was trying to avoid:

for (it = myvec.begin(); it != myvec.end(); ++it) {
if (it->name() == "myname")
break;
}

My comment is this: none of these proposals, including mine, are worth it!

--
Cy
http://home.rochester.rr.com/cyhome/
Jul 22 '05 #9

P: n/a

"Cy Edmunds" <ce******@spamless.rochester.rr.com> wrote in message
news:3R*******************@twister.nyroc.rr.com...
| "Chris ( Val )" <ch******@bigpond.com.au> wrote in message
| news:bt************@ID-110726.news.uni-berlin.de...
| >
| > "Jeff Schwab" <je******@comcast.net> wrote in message
| > news:4s********************@comcast.com...
| > | Daniel T. wrote:
| > | > mikets <mi****@frontline-pcb.com> wrote:

[snip]

| > What do you think ? Comments ?
| >
| > Cheers.
| > Chris Val
| >
| >
|
| Here's the code the OP was trying to avoid:
|
| for (it = myvec.begin(); it != myvec.end(); ++it) {
| if (it->name() == "myname")
| break;
| }
|
| My comment is this: none of these proposals, including mine, are worth it!

You know, when you look at it like that, you're
absolutely right - dang library :-).

Cheers.
Chris Val

Jul 22 '05 #10

P: n/a
Cy Edmunds wrote:
"Chris ( Val )" <ch******@bigpond.com.au> wrote in message
news:bt************@ID-110726.news.uni-berlin.de...
"Jeff Schwab" <je******@comcast.net> wrote in message
news:4s********************@comcast.com...
| Daniel T. wrote:
| > mikets <mi****@frontline-pcb.com> wrote:

[snip]

| > int main()
| > {
| > using namespace std;
| > vector<foo> myvec;
| > myvec.push_back( foo( "joe" ) );
| > myvec.push_back( foo( "myname" ) );
| > myvec.push_back( foo( "harold" ) );
| >
| > vector<foo>::iterator it;
| > for (it = myvec.begin(); it != myvec.end(); ++it) {
| > if (it->name() == "myname")
| > break;
| > }
| > assert( it->name() == "myname" );
| >
| > vector< foo >::iterator it2 = find_if( myvec.begin(), myvec.end(),
| > compose1( bind2nd( equal_to<string>(), "myname" ),
| > mem_fun_ref(&foo::name) ) );
| > assert( it2 == it );
| >
| > cout << "OK" << endl;
| > }
|
| I've been looking for something along those lines. :)

Yeah, but it requires another header, more work, and
besides, it's ugly :-).

Here is another example(I haven't tested it
much), that I came up with:

# include <iostream>
# include <ostream>
# include <string>
# include <vector>

class Person
{
private:
std::string Name;
public:
Person( const std::string& n ) : Name( n ) {}
std::string name() const { return Name; }
};

template<class Object, class DataType> class MatchName
{
private:
DataType ToFind;
DataType (Object::* PMF)();
public:
template<class PtrToFunc>
MatchName( const DataType& Arg, PtrToFunc (Object::* Ptr)() const )
: ToFind( Arg ), PMF( Ptr ) {}

bool operator() ( Object& Element ) const
{
return ToFind == ( Element.*PMF )();
}

// Example overload for std::vector<Person*>
bool operator() (Object*& Element) const
{
return ToFind == (Element ->* PMF)();
}
};

int main()
{
std::vector<Person> V;
V.push_back( Person( "Chris" ) );

if( std::find_if( V.begin(), V.end(),
MatchName<Person, std::string>( "Chris", &Person::name ) ) !=


V.end() )
std::cout << "Working with Chris :-) " << std::endl;

return 0;
}

What do you think ? Comments ?

Cheers.
Chris Val

Here's the code the OP was trying to avoid:

for (it = myvec.begin(); it != myvec.end(); ++it) {
if (it->name() == "myname")
break;
}

My comment is this: none of these proposals, including mine, are worth it!


Well, at least that nasty break could be removed. So could the whole
loop body.

for( it = myvec.begin( );
it != myvec.end( ) && it->name( ) != "myname";
++it );

Jul 22 '05 #11

P: n/a
I would still consider the template solution.

I didn't bother when I had few similar loops. Now I have about
10 such and most probably there will be more.

So if we don't look into the header, the lines with:

if( std::find_if( V.begin(), V.end(),
MatchName<Person, std::string>
( "Chris", &Person::name ) ) != V.end() )
{
}

still look attractive, while almost don't decrease the number of
source lines.

Mike

Jeff Schwab wrote:
Cy Edmunds wrote:
"Chris ( Val )" <ch******@bigpond.com.au> wrote in message
news:bt************@ID-110726.news.uni-berlin.de...
"Jeff Schwab" <je******@comcast.net> wrote in message
news:4s********************@comcast.com...
| Daniel T. wrote:
| > mikets <mi****@frontline-pcb.com> wrote:

[snip]

| > int main()
| > {
| > using namespace std;
| > vector<foo> myvec;
| > myvec.push_back( foo( "joe" ) );
| > myvec.push_back( foo( "myname" ) );
| > myvec.push_back( foo( "harold" ) );
| >
| > vector<foo>::iterator it;
| > for (it = myvec.begin(); it != myvec.end(); ++it) {
| > if (it->name() == "myname")
| > break;
| > }
| > assert( it->name() == "myname" );
| >
| > vector< foo >::iterator it2 = find_if( myvec.begin(),
myvec.end(),
| > compose1( bind2nd( equal_to<string>(), "myname" ),
| > mem_fun_ref(&foo::name) ) );
| > assert( it2 == it );
| >
| > cout << "OK" << endl;
| > }
|
| I've been looking for something along those lines. :)

Yeah, but it requires another header, more work, and
besides, it's ugly :-).

Here is another example(I haven't tested it
much), that I came up with:

# include <iostream>
# include <ostream>
# include <string>
# include <vector>

class Person
{
private:
std::string Name;
public:
Person( const std::string& n ) : Name( n ) {}
std::string name() const { return Name; }
};

template<class Object, class DataType> class MatchName
{
private:
DataType ToFind;
DataType (Object::* PMF)();
public:
template<class PtrToFunc>
MatchName( const DataType& Arg, PtrToFunc (Object::* Ptr)() const )
: ToFind( Arg ), PMF( Ptr ) {}

bool operator() ( Object& Element ) const
{
return ToFind == ( Element.*PMF )();
}

// Example overload for std::vector<Person*>
bool operator() (Object*& Element) const
{
return ToFind == (Element ->* PMF)();
}
};

int main()
{
std::vector<Person> V;
V.push_back( Person( "Chris" ) );

if( std::find_if( V.begin(), V.end(),
MatchName<Person, std::string>( "Chris", &Person::name ) ) !=

V.end() )
std::cout << "Working with Chris :-) " << std::endl;

return 0;
}

What do you think ? Comments ?

Cheers.
Chris Val

Here's the code the OP was trying to avoid:

for (it = myvec.begin(); it != myvec.end(); ++it) {
if (it->name() == "myname")
break;
}

My comment is this: none of these proposals, including mine, are worth
it!

Well, at least that nasty break could be removed. So could the whole
loop body.

for( it = myvec.begin( );
it != myvec.end( ) && it->name( ) != "myname";
++it );


Jul 22 '05 #12

P: n/a

"mikets" <mi****@frontline-pcb.com> wrote in message
news:bt**********@news2.netvision.net.il...
| I would still consider the template solution.
|
| I didn't bother when I had few similar loops. Now I have about
| 10 such and most probably there will be more.
|
| So if we don't look into the header, the lines with:
|
| if( std::find_if( V.begin(), V.end(),
| MatchName<Person, std::string>
| ( "Chris", &Person::name ) ) != V.end() )
| {
| }
|
| still look attractive, while almost don't decrease the number of
| source lines.

Thanks.

Here is another example that you can play with,
but it does not handle <Person*> at this stage:

template<class Object, class Iter, class Criteria, class Method>
inline Iter Find_If( Iter Pos, Iter EndPos,
const Criteria& Value, Method FuncPtr )
{
for( Pos; Pos != EndPos; ++Pos )
if( (Pos->* FuncPtr)() == Value )
return Pos;

return EndPos;
}

int main()
{
std::vector<Person> V;
V.push_back( Person( "Chris" ) );

if( Find_If<Person>( V.begin(), V.end(),
"Chris", &Person::name ) != V.end() )
{
std::cout << "Working with Chris :-) " << std::endl;
}

Please feel free to play around, and modify it to
suit your needs - I'm sure it can be improved further :-).

Cheers.
Chris Val
Jul 22 '05 #13

P: n/a
mikets <mi****@frontline-pcb.com> wrote:
I would still consider the template solution.

I didn't bother when I had few similar loops. Now I have about
10 such and most probably there will be more.

So if we don't look into the header, the lines with:

if( std::find_if( V.begin(), V.end(),
MatchName<Person, std::string>
( "Chris", &Person::name ) ) != V.end() )
{
}

still look attractive, while almost don't decrease the number of
source lines.


You can combine the general usefullness of my solution with the ease of
use of the above solution:

template <typename Object, typename DataType>
inline unary_compose<std::binder2nd<std::equal_to<DataTyp e> >,
std::const_mem_fun_ref_t<const DataType&, Object> >
MatchName(DataType data, const DataType&(Object::*func)() const )
{
using namespace std;
return compose1(bind2nd(equal_to<DataType>(), data),
mem_fun_ref(func));
}

"MatchName" now returns the object necessary to do the job, and is
somewhat easer to use than the above example of yours:

vector<foo>::iterator it2 = find_if( myvec.begin(), myvec.end(),
MatchName( string("myname"), &foo::name ) );

We can generalize that some more and get:

template <typename Func, typename T>
inline unary_compose<std::binder2nd<std::equal_to<T> >, Func >
MatchReturnTo( T data, Func func )
{
using namespace std;
return compose1(bind2nd(equal_to<T>(), data), func);
}

Which would work with any function, function object, member-function, or
pointer to member function that returns the same type that "data" is.
For this example it would be used thus:

vector<foo>::iterator it2 = find_if(myvec.begin(), myvec.end(),
MatchReturnTo(string("myname"), mem_fun_ref(&foo::name)));
Jul 22 '05 #14

P: n/a

"Daniel T." <po********@eathlink.net> wrote in message
news:po******************************@news01.east. earthlink.net...
| mikets <mi****@frontline-pcb.com> wrote:
|
| > I would still consider the template solution.
| >
| > I didn't bother when I had few similar loops. Now I have about
| > 10 such and most probably there will be more.
| >
| > So if we don't look into the header, the lines with:
| >
| > if( std::find_if( V.begin(), V.end(),
| > MatchName<Person, std::string>
| > ( "Chris", &Person::name ) ) != V.end() )
| > {
| > }
| >
| > still look attractive, while almost don't decrease the number of
| > source lines.
|
| You can combine the general usefullness of my solution with the ease of
| use of the above solution:

[ snipped some interesting stuff :-),
that I will look into, thanks Daniel ].

Cheers.
Chris Val
Jul 22 '05 #15

This discussion thread is closed

Replies have been disabled for this discussion.