Help with template find_if predicate



 DEVELOP > c-Plus-Plus > Help with template find_if predicate

LINK TO THIS PAGE  


rating :  0   |  0


  Page 1 of 1

1

 
Topic: DEVELOP > c-Plus-Plus
User: "mikets"
Date: 04 Jan 2004 11:19:10 AM
Object: Help with template find_if predicate
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.
.

User: "Cy Edmunds"

Title: Re: Help with template find_if predicate 04 Jan 2004 12:44:51 PM
"mikets" <mikets@frontline-pcb.com> wrote in message
news:bt9hvu$jci$1@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/
.

User: "Chris \ Val "

Title: Re: Help with template find_if predicate 05 Jan 2004 12:12:12 AM
"mikets" <mikets@frontline-pcb.com> wrote in message
news:bt9hvu$jci$1@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.
This could have been simplified with a function object as follows:
# 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; }
};
class MatchName
{
private:
std::string ToFind;
public:
template<typename T>
MatchName( const T& Arg ) : ToFind( Arg ) {}
template<typename U>
bool operator() ( const U& Obj ) const
{
return ToFind == Obj.name();
}
};
int main()
{
std::vector<Person> V;
V.push_back( Person( "Melvin" ) );
if( std::find_if( V.begin(), V.end(),
MatchName( "Melvin" ) ) != V.end() )
std::cout << "Found " << std::endl;
return 0;
}
Cheers.
Chris Val
.

User: "Howard Hinnant"

Title: Re: Help with template find_if predicate 04 Jan 2004 01:28:39 PM
In article <bt9hvu$jci$1@news2.netvision.net.il>,
mikets <mikets@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
.
User: "Rolf Magnus"

Title: Re: Help with template find_if predicate 05 Jan 2004 05:19:35 AM
Howard Hinnant wrote:

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

What is std::tr1?
.
User: "tom_usenet"

Title: Re: Help with template find_if predicate 05 Jan 2004 07:04:34 AM
On Mon, 05 Jan 2004 12:19:35 +0100, Rolf Magnus <ramagnus@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/docs/papers/2003/n1540.pdf
Tom
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
.



User: "Daniel T."

Title: Re: Help with template find_if predicate 05 Jan 2004 12:45:31 AM
mikets <mikets@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;
}
.
User: "Jeff Schwab"

Title: Re: Help with template find_if predicate 05 Jan 2004 05:52:57 AM
Daniel T. wrote:

mikets <mikets@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. :)
.
User: "Chris \ Val "

Title: Re: Help with template find_if predicate 05 Jan 2004 06:41:09 AM
"Jeff Schwab" <jeffplus@comcast.net> wrote in message
news:4sWdnfb3c-9g0mSiRVn-jw@comcast.com...
| Daniel T. wrote:
| > mikets <mikets@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
.
User: "Cy Edmunds"

Title: Re: Help with template find_if predicate 05 Jan 2004 05:56:47 PM
"Chris ( Val )" <chrisval@bigpond.com.au> wrote in message
news:btbm18$5aqa6$1@ID-110726.news.uni-berlin.de...


"Jeff Schwab" <jeffplus@comcast.net> wrote in message
news:4sWdnfb3c-9g0mSiRVn-jw@comcast.com...
| Daniel T. wrote:
| > mikets <mikets@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/
.
User: "Chris \ Val "

Title: Re: Help with template find_if predicate 05 Jan 2004 06:38:12 PM
"Cy Edmunds" <cedmunds@spamless.rochester.rr.com> wrote in message
news:3RmKb.55793$q55.51333@twister.nyroc.rr.com...
| "Chris ( Val )" <chrisval@bigpond.com.au> wrote in message
| news:btbm18$5aqa6$1@ID-110726.news.uni-berlin.de...
| >
| > "Jeff Schwab" <jeffplus@comcast.net> wrote in message
| > news:4sWdnfb3c-9g0mSiRVn-jw@comcast.com...
| > | Daniel T. wrote:
| > | > mikets <mikets@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
.

User: "Jeff Schwab"

Title: Re: Help with template find_if predicate 05 Jan 2004 07:23:54 PM
Cy Edmunds wrote:

"Chris ( Val )" <chrisval@bigpond.com.au> wrote in message
news:btbm18$5aqa6$1@ID-110726.news.uni-berlin.de...

"Jeff Schwab" <jeffplus@comcast.net> wrote in message
news:4sWdnfb3c-9g0mSiRVn-jw@comcast.com...
| Daniel T. wrote:
| > mikets <mikets@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 );
.
User: "mikets"

Title: Re: Help with template find_if predicate 06 Jan 2004 01:17:13 AM
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 )" <chrisval@bigpond.com.au> wrote in message
news:btbm18$5aqa6$1@ID-110726.news.uni-berlin.de...

"Jeff Schwab" <jeffplus@comcast.net> wrote in message
news:4sWdnfb3c-9g0mSiRVn-jw@comcast.com...
| Daniel T. wrote:
| > mikets <mikets@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 );

.
User: "Chris \ Val "

Title: Re: Help with template find_if predicate 06 Jan 2004 08:38:40 AM
"mikets" <mikets@frontline-pcb.com> wrote in message
news:btdnf5$5sp$1@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
.

User: "Daniel T."

Title: Re: Help with template find_if predicate 07 Jan 2004 07:19:35 AM
mikets <mikets@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<DataType> >,
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)));
.
User: "Chris \ Val "

Title: Re: Help with template find_if predicate 07 Jan 2004 08:36:22 AM
"Daniel T." <postmaster@eathlink.net> wrote in message
news:postmaster-CBD061.08193507012004@news01.east.earthlink.net...
| mikets <mikets@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
.







User: "mikets"

Title: Re: Help with template find_if predicate 05 Jan 2004 02:15:32 AM
Thanks, Daniel.
This is great!
Mike.
Daniel T. wrote:

mikets <mikets@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;
}

.


User: "CrayzeeWulf"

Title: Re: Help with template find_if predicate 04 Jan 2004 01:29:19 PM
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
.
User: "mikets"

Title: Re: Help with template find_if predicate 05 Jan 2004 01:40:49 AM
Thank you all.
I feel, CrayzeeWulf's suggestion is the most close to what I
need. Definitely, the member method name() was for example only.
In fact, member methods vary also, not necessarily - it may be
also id(), or any other method, with the corresponding value type.
Mike.
CrayzeeWulf wrote:

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,

.



  Page 1 of 1

1

 


Related Articles
 

NEWER

pg.1232     pg.940     pg.716     pg.544     pg.412     pg.311     pg.234     pg.175     pg.130     pg.96     pg.70     pg.50     pg.35     pg.24     pg.16     pg.10     pg.6     pg.3     pg.1

OLDER