mem_fun vs mem_fun_ref

I

Ioannis Vranos

What is the exact difference between mem_fun and mem_fun_ref, since in
all examples I looked at, they are used in exactly the same way?
 
V

Victor Bazarov

Ioannis Vranos said:
What is the exact difference between mem_fun and mem_fun_ref, since in all
examples I looked at, they are used in exactly the same way?

They return objects of different types, mem_fun_t and mem_fun_ref_t,
whose member functions operator(), in turn, take different arguments,
the former takes T*, the latter takes T&. RTFM.

V
 
P

Pete Becker

Ioannis said:
What is the exact difference between mem_fun and mem_fun_ref, since in
all examples I looked at, they are used in exactly the same way?

mem_fun returns an object that can be called with a pointer to an
object; mem_fun_ref returns an object that can be called with an object
or a reference to an object. Like this:

#include <functional>
#include <iostream>
using std::mem_fun; using std::mem_fun_ref;
using std::cout;

struct S
{
void f()
{
cout << "called S::f\n";
}
};

int main()
{
S s;
S *sp = &s;
mem_fun(&S::f)(sp);
mem_fun_ref(&S::f)(s);
return 0;
}

TR1's mem_fn doesn't require this early a decision; mem_fn(&S::f) can be
called with an object, a reference to an object, a pointer to an object,
or a smart pointer to an object.
 
D

Dietmar Kuehl

Ioannis said:
What is the exact difference between mem_fun and mem_fun_ref, since in
all examples I looked at, they are used in exactly the same way?

The difference is how the object the member function is called on
is passed to the functor: for a functor returned from 'mem_fun()' a
pointer to the object is passed. For a functor returned from
'mem_fun_ref()' a reference to the object is passed. Although both
version could be folded into just one functor overloading the function
call operator, this could obscure certain problems.
 
I

Ioannis Vranos

Thanks for the clarification fellows. However I can't make the following
to work (taken and modified from another message thread):


#include <vector>
#include <algorithm>
#include <functional>


class B {};
class C {};

class A
{
public:
virtual C foo(const B &) const { return C(); }
};



int main()
{
using namespace std;

A obj;
A &a = obj;

vector<B> in(42);

vector<C> out(in.size());

// Here's the problem
transform(in.begin(), in.end(), out.begin(),
(mem_fun_ref(&A::foo) (a));
}
 
P

Pete Becker

Ioannis said:
(mem_fun_ref(&A::foo) (a));

Since A::foo takes one argument you have to pass two arguments to the
function call operator of the object returned by mem_fun_ref -- one for
the object to call the member function with, and one for the explicit
argument. mem_fun_ref(&A::foo)(a) tries to call it with only one
argument. And even if it took only one, you wouldn't call its operator()
from here; transform will call it.

So back up a bit. mem_fun_ref in this case returns an object whose
function call operator takes two arguments. You want to *bind* the value
'a' to the *first* argument, and pass the argument provided by transform
as the second argument. To *bind* the *first* argument use bind1st:

bind1st(mem_fun_ref(&A::foo), obj)
 
I

Ioannis Vranos

Pete said:
Since A::foo takes one argument you have to pass two arguments to the
function call operator of the object returned by mem_fun_ref -- one for
the object to call the member function with, and one for the explicit
argument. mem_fun_ref(&A::foo)(a) tries to call it with only one
argument. And even if it took only one, you wouldn't call its operator()
from here; transform will call it.

So back up a bit. mem_fun_ref in this case returns an object whose
function call operator takes two arguments. You want to *bind* the value
'a' to the *first* argument, and pass the argument provided by transform
as the second argument. To *bind* the *first* argument use bind1st:

bind1st(mem_fun_ref(&A::foo), obj)


Thanks for the reply however the code:

#include <vector>
#include <algorithm>
#include <functional>


class B {};
class C {};

class A
{
public:
virtual C foo(const B &) const { return C(); }
};



int main()
{
using namespace std;

A obj;
A &a = obj;

vector<B> in(42);

vector<C> out(in.size());

transform(in.begin(), in.end(), out.begin(),
bind1st(mem_fun_ref(&A::foo), obj) );
}



doesn't compile either:

C:\c>g++ temp.cpp -o temp.exe
C:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/stl_f
unction.h: In instantiation of
`std::binder1st<std::const_mem_fun1_ref_t<C, A, c
onst B&> >':
temp.cpp:29: instantiated from here
C:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/stl_f
unction.h:406: error: forming reference to reference type `const B&'
C:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/stl_f
unction.h:412: error: forming reference to reference type `const B&'
C:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/stl_a
lgo.h: In function `_OutputIterator std::transform(_InputIterator,
_InputIterato
r, _OutputIterator, _UnaryOperation) [with _InputIterator =
__gnu_cxx::__normal_
iterator<B*, std::vector<B, std::allocator<B> > >, _OutputIterator =
__gnu_cxx::
__normal_iterator<C*, std::vector<C, std::allocator<C> > >,
_UnaryOperation = st
d::binder1st<std::const_mem_fun1_ref_t<C, A, const B&> >]':
temp.cpp:29: instantiated from here
C:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/stl_a
lgo.h:789: error: no match for call to
`(std::binder1st<std::const_mem_fun1_ref_
t<C, A, const B&> >) (B&)'

C:\c>
 
I

Ioannis Vranos

However this compiles:


#include <vector>
#include <algorithm>
#include <functional>


class B {};
class C {};

class A
{
public:

virtual C foo(const B) const { return C(); }
};



int main()
{
using namespace std;

A obj;
A &a = obj;

vector<B> in(42);

vector<C> out(in.size());

transform(in.begin(), in.end(), out.begin(),
bind1st(mem_fun_ref(&A::foo), obj) );
}



Isn't there any way to maintain the reference argument in foo?
 
R

red floyd

Ioannis said:
Thanks for the reply however the code:

#include <vector>
#include <algorithm>
#include <functional>


class B {};
class C {};

class A
{
public:
virtual C foo(const B &) const { return C(); }
};



int main()
{
using namespace std;

A obj;
A &a = obj;

vector<B> in(42);

vector<C> out(in.size());

transform(in.begin(), in.end(), out.begin(),
bind1st(mem_fun_ref(&A::foo), obj) );
}


You're looking at this backwards. mem_fun_ref will work on the members
of "in", which are B's, not A's. Therefore foo (returning a C) must be
a member function of B!!!!!! Second, A::foo, as currently implemented
takes a B as an object.

You're essentially writing

class B { };
class C { };
class A {
public:
C foo(const B&);
};

A obj;
B b;

C = b.foo(A);

Does that help a bit?
 
I

Ioannis Vranos

red said:
You're looking at this backwards. mem_fun_ref will work on the members
of "in", which are B's, not A's. Therefore foo (returning a C) must be
a member function of B!!!!!!


Actually no. After the modification I made foo accepting const B objects
and not const B references, it works. However I did not say everything
is easy to understand completely.


Probably it will take many years until we become completely familiar in
the language. :)
 
P

Pete Becker

Ioannis said:
Isn't there any way to maintain the reference argument in foo?

Apparently not. <g> STL is pretty aggressive about dealing with
arguments by value.
 
I

Ioannis Vranos

Pete said:
Apparently not. <g> STL is pretty aggressive about dealing with
arguments by value.


OK, thanks for the info. However may you explain how this works?


class A
{
public:

virtual C foo(const B) const { return C(); }
};

// ...

transform(in.begin(), in.end(), out.begin(),
bind1st(mem_fun_ref(&A::foo), obj) );



A::foo() takes one argument. mem_fun_ref applies the member function to
the objects passed (usually the objects of the sequence). bind1st binds
an argument as the first argument of a *binary function*.


How does it end up working? :)
 
P

Pete Becker

Ioannis said:
A::foo() takes one argument. mem_fun_ref applies the member function to
the objects passed (usually the objects of the sequence). bind1st binds
an argument as the first argument of a *binary function*.


How does it end up working? :)

A::foo() takes one explicit argument and an implicit 'this' pointer.
When you call mem_fun(&A::foo) or mem_fun_ref(&A::foo) you get back an
object that has a function call operator that take two arguments. The
first is the object that the member function should be applied to (which
provides the 'this' pointer) and the second is the explicit argument to
the member function.

For example:

A a;
A *ap = &a;
B b;

mem_fun_ref(&A::foo)(a, b) is equivalent to a.foo(b).
mem_fun(&A::foo)(ap, b) is equivalent to ap->foo(b).
 

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,731
Messages
2,569,432
Members
44,832
Latest member
GlennSmall

Latest Threads

Top