for_each loop on a map without a functor

N

nguillot

Hello

I used to loop on a std::map<k, d> to act on the data (d) like that (d
being a class with setIntMember method):

typedef std::map<k, d> tMap;

struct setIntMember
{
setIntMember(int j) : i(j) {}
void operator()(tMap::value_type& pair)
{ pair.second.setIntMember(i); }
int i;
};

The loop being:
for_each(m.begin(), m.end(), setIntMember(4));

I searched for a method to write all in the for_each loop (to avoid
increasing the functors).

We need a function returning the second member of the pair
tMap::value_type,
and their is the SGI template:

template<typename _Pair>
struct Select2nd : public unary_function<_Pair,
typename _Pair::second_type>
{
typename _Pair::second_type& operator()(_Pair& __x) const
{ return __x.second; }

const typename _Pair::second_type& operator()(const _Pair&
__x) const
{ return __x.second; }
};

But I didn't manage to write a single line to perform the for_each
loop, thanks to Select2nd with for_each, bind2nd and mem_fun and
mem_fun1

I didn't manage with boost::bind (on VC++ 6.0):
With boost, I can access the objects like that:
for_each(m.begin(), m.end(),
boost::bind(&d::Trace, boost::bind(&tMap::value_type::second,
_1)));
but the d::Trace method is called on a temporary object, so I cannot
modify the content of the objects contained in the map.

Some ideas? Thanks in advance.

Nicolas.
 
D

Daniel T.

Hello

I used to loop on a std::map<k, d> to act on the data (d) like that (d
being a class with setIntMember method):

    typedef std::map<k, d> tMap;

    struct setIntMember
    {
        setIntMember(int j) : i(j) {}
        void operator()(tMap::value_type& pair)
{ pair.second.setIntMember(i); }
        int i;
    };

The loop being:
    for_each(m.begin(), m.end(), setIntMember(4));

I searched for a method to write all in the for_each loop (to avoid
increasing the functors).

We need a function returning the second member of the pair
tMap::value_type,
and their is the SGI template:

    template<typename _Pair>
    struct Select2nd : public unary_function<_Pair,
                          typename _Pair::second_type>
    {
        typename _Pair::second_type& operator()(_Pair& __x) const
        { return __x.second; }

        const typename _Pair::second_type& operator()(const _Pair&
__x) const
        { return __x.second; }
    };

But I didn't manage to write a single line to perform the for_each
loop, thanks to Select2nd with for_each, bind2nd and mem_fun and
mem_fun1

I didn't manage with boost::bind (on VC++ 6.0):
With boost, I can access the objects like that:
    for_each(m.begin(), m.end(),
        boost::bind(&d::Trace, boost::bind(&tMap::value_type::second,
_1)));
but the d::Trace method is called on a temporary object, so I cannot
modify the content of the objects contained in the map.

Some ideas?

Just use the functor you created. It's simple and clean... You might
want to generalized it a little bit:

template < typename Pair, typename Op >
class CallFuncOn2nd_t {
Op fn;
public:
CallFuncOn2nd_t( Op fn ): fn(fn) { }
typename Op::result_type operator()( Pair& v ) const {
return fn( v.second );
}
};

template < typename Pair, typename Op >
CallFuncOn2nd_t<Pair, Op> callFuncOn2nd( Op fn ) {
return CallFuncOn2nd_t<Pair, Op>( fn );
}

for_each(m.begin(), m.end(),

callFuncOn2nd<tMap::value_type>(bind2nd(mem_fun_ref(&d::setIntMember),
4)));
 
E

Eric.Malenfant

Hello

I used to loop on a std::map<k, d> to act on the data (d) like that (d
being a class with setIntMember method):

typedef std::map<k, d> tMap;

struct setIntMember
{
setIntMember(int j) : i(j) {}
void operator()(tMap::value_type& pair)
{ pair.second.setIntMember(i); }
int i;
};

The loop being:
for_each(m.begin(), m.end(), setIntMember(4));

I searched for a method to write all in the for_each loop (to avoid
increasing the functors).
[snip]


I didn't manage with boost::bind (on VC++ 6.0):
With boost, I can access the objects like that:
for_each(m.begin(), m.end(),
boost::bind(&d::Trace, boost::bind(&tMap::value_type::second,
_1)));
but the d::Trace method is called on a temporary object, so I cannot
modify the content of the objects contained in the map.

For the boost::bind part, your case looks very much like what is
discussed here: http://lists.boost.org/boost-users/2007/01/24599.php
(Look at Peter Dimov's reply)
 
N

nguillot

Just use the functor you created. It's simple and clean... You might
want to generalized it a little bit:

template < typename Pair, typename Op >
class CallFuncOn2nd_t {
Op fn;
public:
CallFuncOn2nd_t( Op fn ): fn(fn) { }
typename Op::result_type operator()( Pair& v ) const {
return fn( v.second );
}

};

template < typename Pair, typename Op >
CallFuncOn2nd_t<Pair, Op> callFuncOn2nd( Op fn ) {
return CallFuncOn2nd_t<Pair, Op>( fn );

}

for_each(m.begin(), m.end(),

callFuncOn2nd<tMap::value_type>(bind2nd(mem_fun_ref(&d::setIntMember),
4)));

Ok, thanks, that's was exactly what I wanted to do!

But callFuncOn2nd<tMap::value_type>(bind2nd... fails to compile: the
second template argument seems to be required.
We must set the second template argument as a class that
has ::result_type, so I tried a std::unary_function<d, bool> (if
d::setIntMember returns a bool), but even if bind2nd could be
converted to unary_function (what fails) a unary function doesn't have
a () operator.
And I didn't manage write the second argument to be
std::binder2nd<std::binary_function<d*, int, bool> > or something like
that: it doesn't compile.

So the question: how write the for_each line?
Or how to modify the callFuncOn2nd to auto discover the type (that
woulkd be nice, but as Op is the typeof fn (member of the class), we
have to put Op a a class template argument...

Thanks for help.

Nicolas.
 
D

Daniel T.

Ok, thanks, that's was exactly what I wanted to do!

But callFuncOn2nd<tMap::value_type>(bind2nd... fails to compile: the
second template argument seems to be required.
We must set the second template argument as a class that
has ::result_type, so I tried a std::unary_function<d, bool> (if
d::setIntMember returns a bool), but even if bind2nd could be
converted to unary_function (what fails) a unary function doesn't have
a () operator.
And I didn't manage write the second argument to be
std::binder2nd<std::binary_function<d*, int, bool> > or something like
that: it doesn't compile.

So the question: how write the for_each line?

Hmm, the for_each line I wrote above compiles fine for me. What
compiler are you using?
 
D

Daniel T.

I tried on VC++ 6.0 and on visual studio 2005...
and you

Visual Sutdio 2005 compiles the following just fine:
=== begine code ===
#include <algorithm>
#include <map>

using namespace std;

typedef int k;

class d {
public:
void setIntMember( int i ) { }
};

template < typename Pair, typename Op >
class CallFuncOn2nd_t {
Op fn;
public:
CallFuncOn2nd_t( Op fn ): fn(fn) { }
typename Op::result_type operator()( Pair& v ) const {
return fn( v.second );
}
};

template < typename Pair, typename Op >
CallFuncOn2nd_t<Pair, Op> callFuncOn2nd( Op fn ) {
return CallFuncOn2nd_t<Pair, Op>( fn );
}

typedef std::map<k, d> tMap;

int main(){
tMap m;
for_each(m.begin(), m.end(),

callFuncOn2nd<tMap::value_type>( bind2nd( mem_fun_ref( &d::setIntMember ),
4 ) ) );
}
=== end code ===
 
D

Daniel T.

nguillot said:
I used to loop on a std::map<k, d> to act on the data (d) like that (d
being a class with setIntMember method):

typedef std::map<k, d> tMap;

struct setIntMember
{
setIntMember(int j) : i(j) {}
void operator()(tMap::value_type& pair)
{ pair.second.setIntMember(i); }
int i;
};

The loop being:
for_each(m.begin(), m.end(), setIntMember(4));

I searched for a method to write all in the for_each loop (to avoid
increasing the functors).

Some ideas? Thanks in advance.

I finally got it...

class Foo {
public:
void bar( int i ) { }
};

typedef map<int, Foo> map_t;

int main() {
map_t pot;
for_each( pot.begin(), pot.end(),
bind( &Foo::bar, bind(&map_t::value_type::second, _1 ), 4 ) );
}

I verified that this does in fact call Foo::bar on the object within
the map, not on a temporary.
 
J

Jerry Coffin

Hello

I used to loop on a std::map<k, d> to act on the data (d) like that (d
being a class with setIntMember method):

typedef std::map<k, d> tMap;

struct setIntMember
{
setIntMember(int j) : i(j) {}
void operator()(tMap::value_type& pair)
{ pair.second.setIntMember(i); }
int i;
};

The loop being:
for_each(m.begin(), m.end(), setIntMember(4));

I searched for a method to write all in the for_each loop (to avoid
increasing the functors).

In this case, I'm pretty sure a simple for loop is really much more
readable than anything using for_each:

for (std::map<k,d>::iterator p=m.begin(), p!=m.end(), ++p)
p->second = 4;

Boost::lambda is often useful when you want to avoid (explicitly)
creating a functor, but I don't believe it works for this particular
case. As we've already seen in the rest of the thread, the code to make
for_each do the job ends up ugly and MUCH less readable than an explicit
loop. I know we'd all like to use an algorithm, but in this case the
cost is high and the benefit essentially nonexistent.
 
N

nguillot

Visual Sutdio 2005 compiles the following just fine:
=== begine code ===
#include <algorithm>
#include <map>

using namespace std;

typedef int k;

class d {
public:
void setIntMember( int i ) { }

};

template < typename Pair, typename Op >
class CallFuncOn2nd_t {
Op fn;
public:
CallFuncOn2nd_t( Op fn ): fn(fn) { }
typename Op::result_type operator()( Pair& v ) const {
return fn( v.second );
}

};

template < typename Pair, typename Op >
CallFuncOn2nd_t<Pair, Op> callFuncOn2nd( Op fn ) {
return CallFuncOn2nd_t<Pair, Op>( fn );

}

typedef std::map<k, d> tMap;

int main(){
tMap m;
for_each(m.begin(), m.end(),

callFuncOn2nd<tMap::value_type>( bind2nd( mem_fun_ref( &d::setIntMember ),
4 ) ) );}

=== end code ===

ARF !!

It's my fault.
I had not seen the function callOn2nd. I only saw the class!
So, ok, the code compiles (on g++).

I don't understand why we can't define only the class (if we do that
and call directly the class in the for_each:
for_each(m.begin(),
m.end(),CallFuncOn2nd_t<tMap::value_type>(bind2nd(mem_fun_ref(&d::setIntMember),
4)));
it doesn't compile:
wrong number of template arguments (1, should be 2) provided for
`template<class Pair, class Op> class CallFuncO
n2nd_t')

the same loop with the function is ok.
I would think that in
CallFuncOn2nd_t<tMap::value_type>(bind2nd(...)
the constructor would "set" the Op template arg, the second being
specified between <>.

So this solution is ok, modify the object within the map, not a
temporary.
And I think this form is not MUCH less readable than an explicit
loop ;-)

Thanks again !

An explanation on why we can't use the functor CallFuncOn2nd_t without
the function callFuncOn2nd?
 
D

Daniel T.

nguillot said:
ARF !!

It's my fault.
I had not seen the function callOn2nd. I only saw the class!
So, ok, the code compiles (on g++).

I don't understand why we can't define only the class (if we do that
and call directly the class in the for_each:
for_each(m.begin(),
m.end(),CallFuncOn2nd_t<tMap::value_type>(bind2nd(mem_fun_ref(&d::setIntMember
),
4)));
it doesn't compile:
wrong number of template arguments (1, should be 2) provided for
`template<class Pair, class Op> class CallFuncO
n2nd_t')

the same loop with the function is ok.
I would think that in
CallFuncOn2nd_t<tMap::value_type>(bind2nd(...)
the constructor would "set" the Op template arg, the second being
specified between <>.

The compiler will not infer types on template classes, only functions.
Both template parameters must be declared when using the class directly.
i.e., you would have to do this:

for_each( m.begin(), m.end(),
CallFuncOn2nd_t< tMap::value_type,
So this solution is ok, modify the object within the map, not a
temporary.

I think the boost bind solution is better.
 
N

nguillot

The compiler will not infer types on template classes, only functions.
Both template parameters must be declared when using the class directly.
i.e., you would have to do this:

for_each( m.begin(), m.end(),
CallFuncOn2nd_t< tMap::value_type,


I think the boost bind solution is better.

About the boost solution,
don't you have the following error:

main.cpp:84: instantiated from here
../boost/bind/mem_fn_template.hpp:148: error: invalid conversion from
`const Foo*
' to `Foo*'

See boost doc about this problem: http://www.boost.org/libs/bind/bind.html#Limitations

Your code compiles and works on visual studi VC++6.0
But it doesn't on g++ and on visual studio 2005.

Which compiler did you use?

Thank you

Nicolas
 
D

Daniel T.

nguillot said:
About the boost solution,
don't you have the following error:

main.cpp:84: instantiated from here
./boost/bind/mem_fn_template.hpp:148: error: invalid conversion from
`const Foo*
' to `Foo*'

No, I don't. Let's make sure we are talking about the same code...

using namespace std;
using namespace boost::lambda;

class Foo {
public:
void bar( int i ) { }
};

typedef map<int, Foo> map_t;

int main() {
map_t pot;
for_each( pot.begin(), pot.end(),
bind( &Foo::bar, bind(&map_t::value_type::second, _1 ), 4 ) );
}
See boost doc about this problem:
http://www.boost.org/libs/bind/bind.html#Limitations

Your code compiles and works on visual studi VC++6.0
But it doesn't on g++ and on visual studio 2005.

Which compiler did you use?

gcc 4.0.
 
N

nguillot

No, I don't. Let's make sure we are talking about the same code...

using namespace std;
using namespace boost::lambda;

class Foo {
public:
void bar( int i ) { }

};

typedef map<int, Foo> map_t;

int main() {
map_t pot;
for_each( pot.begin(), pot.end(),
bind( &Foo::bar, bind(&map_t::value_type::second, _1 ), 4 ) );

}



gcc 4.0.

Hello

My fault again, I was using boost::bind instead of
boost::lambda::bind.
This time, it's good.

Thank you very much!

Nicolas.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top