Topic: Calling member functions from STL: a solution.
Author: austern@isolde.mti.sgi.com (Matt Austern)
Date: 1996/06/19 Raw View
In article <4pa3ku$op8@hermes.synopsys.com> jbuck@Synopsys.COM (Joe
Buck) writes:
> Could someone post a more detailed description of Stroustrup's proposal?
> Matt mentions the adaptors mem_fun, mem_fun_ref, mem_fun1 and
> mem_fun1_ref; presumably there are corresponding template classes
> for each, also while I can guess what mem_fun and mem_fun_ref look
> like, I'm unclear about mem_fun1. Does the operator() take two arguments?
Sorry, I guess my explanation was a bit terse. The full proposal (now
described in section 20.3.8 [lib.member.pointer.adaptors] of the May
WP) includes four types, mem_fun_t, mem_fun1_t, mem_fun_ref_t,
and mem_fun1_ref_t, and four functions, mem_fun, mem_fun1,
mem_fun_ref, and mem_fun1_ref.
Mem_fun_t is a function object that inherits from
unary_function<T*, S> (that is, it takes a single argument of
type T* and returns S), mem_fun_ref_t takes a T and returns
an S, mem_fun1_t takes a T* and an A and returns an S,
and mem_fun1_ref_t takes a T and an A and returns an S.
Normally, of course, you won't use these function object types
directly, you'll just use the adaptor functions. mem_fun
takes a single argument of type S (T::*)() (that is, its argument
is a pointer to a member function of T that takes no argument
and returns an S), and returns an object of class
mem_fun_t<S, T>: a function object whose argument is T* and
whose return type is S.
mem_fun_ref also takes a single argument of type S (T::*)(),
but it returns a function object whose argument is T and whose
return type is S.
mem_fun1 and mem_fun1_ref do the same thing for member functions that
take a single argument: mem_fun1 takes an argument of type S (T::*)(A)
and returns a binary function object whose arguments are T* and A, and
mem_fun1_ref takes an argument of type S (T::*)(A) and returns a
binary function object whose arguments are T and A.
--
Matt Austern
SGI: MTI Compilers Group
austern@isolde.mti.sgi.com
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: jbuck@Synopsys.COM (Joe Buck)
Date: 1996/06/08 Raw View
austern@mti.mti.sgi.com writes:
coryan@riemann.mat.puc.cl (Carlos O'Ryan) proposed templates and
adapters that use pointers to member functions.
Matt Austern writes:
>Bjarne Stroustrup made a very similar proposal, for very similar
>reasons, in "A Standard Adaptor to Support Polymorphic Containers"
>(X3J16/96-0030 = WG21/N0848). His proposal was accepted, with minor
>modifications, at the Santa Cruz meeting in March '96.
>If you have a vector V containing pointers to class Foo, and you want
>to apply the member function to all of them, then you'll do something
>like this: for_each(V.begin(), V.end(), mem_fun(&Foo::f)).
Could someone post a more detailed description of Stroustrup's proposal?
Matt mentions the adaptors mem_fun, mem_fun_ref, mem_fun1 and
mem_fun1_ref; presumably there are corresponding template classes
for each, also while I can guess what mem_fun and mem_fun_ref look
like, I'm unclear about mem_fun1. Does the operator() take two arguments?
--
-- Joe Buck <jbuck@synopsys.com> (not speaking for Synopsys, Inc)
Work for something because it is good,
not just because it stands a chance to succeed. -- Vaclav Havel
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: coryan@riemann.mat.puc.cl (Carlos O'Ryan)
Date: 1996/05/30 Raw View
Hi,
Using the algorithm library to call member functions is (IMHO)
awkward if not impossible, if someone can point me a reasonable
solution with the current STL definition (April/1995 DWP) I'd be
thankful, meanwhile I propose some idioms (or should I say patterns)
that could help as solutions.
MOTIVATION:
Let us suppose we have some class like:
//
class Foo {
public:
Foo(int v) : value(v) {}
// defaul dtor, cpy_ctor & operator=
int f(int i)
{
cerr << "Foo::f(" << i+value << ")" << endl;
return i+value;
}
private:
int value;
};
//
should we have a set of int's and like to call F::f for each
of them, we have to write:
//
extern set<int> intset;
extern Foo foo;
void g()
{
for(set<int>::iterator i = intset.begin(); i != intset.end(); i++) {
Foo.f(*i);
}
}
//
IMHO one should try to use the standard algorithms, the
following "helper class" serves as an interface:
//
class FooCaller : public std::unary_function<int,int> {
public:
FooCaller(Foo* bar) : foo(bar) {}
int operator()(int i) { return foo->f(i); }
private:
Foo* foo;
};
extern set<int> intset;
extern Foo foo;
void g()
{
for_each(intset.begin(); intset.end(); FooCaller(&foo));
}
//
Writing a 'FooCaller' for each class and/or member is tedious
and error prone, some parameterized class is needed that serves as an
interface from member functions to STL functional objects.
SOLUTION
As a first approach define the following template:
//
template<class Object, class Arg, class Result>
class pointer_to_member_function
: public std::binary_function<Arg,Result>
{
public:
pointer_to_member_function(Object* o,
Result (Object::*m)(Arg))
: object(o), member(m)
{
}
Result operator()(Arg a) { return (object->*member)(a); }
private:
Object* const object;
Result (Object::*member)(Arg);
};
//
now our previous example boils down to:
//
extern set<int> intset;
extern Foo foo;
void g()
{
for_each(intset.begin(); intset.end();
pointer_to_member_function<Foo,int,int>(&foo,Foo::f));
}
//
still the technique does not cope well with the following case:
//
extern list<Foo> fool;
void h()
{
for(list<Foo>::iterator i = fool.begin(); i != fool.end(); i++) {
(*i).f(5)
}
}
//
so we modify the 'pointer_to_member_function' to take the
object as a "parameter":
//
template<class Object, class Arg, class Result>
class pointer_to_member_function
: public std::binary_function<Object*,Arg,Result>
{
public:
pointer_to_member_function(Result (Object::*m)(Arg))
: member(m)
{
}
Result operator()(Object* o, Arg a)
{
return (o->*member)(a);
}
private:
Result (Object::*member)(Arg);
};
//
now our first example becomes:
//
extern set<int> intset;
extern Foo foo;
void g()
{
for_each(intset.begin(); intset.end();
bind1st(pointer_to_member_function<Foo,int,int>(Foo::f),
&foo));
}
//
and the second example becomes:
//
extern list<Foo> fool;
void h()
{
for_each(fool.begin(); fool.end();
bind2nd(pointer_to_member_function<Foo,int,int>(Foo::f),
5));
}
}
//
CONCLUSION
In my opinion the class extends the notion of "functional
object" in th STL to member functions without any seams. If it is not
too late it could be included is the STL.
NOTES
Some helper classes and functions are needed, for instance:
how to handle member functions with two arguments and some functions
to create the "pointer_to_member_function" from the argument (much
like 'bind1st' does).
--
Carlos O'Ryan (coryan@mat.puc.cl)
#include <std.disclaimer>
#include <cute.quote> // "Speak softly and carry a megawatt laser"
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: austern@isolde.mti.sgi.com (Matt Austern)
Date: 1996/05/30 Raw View
In article <CORYAN.96May30004114@riemann.mat.puc.cl>
coryan@riemann.mat.puc.cl (Carlos O'Ryan) writes:
> Using the algorithm library to call member functions is (IMHO)
> awkward if not impossible, if someone can point me a reasonable
> solution with the current STL definition (April/1995 DWP) I'd be
> thankful, meanwhile I propose some idioms (or should I say patterns)
> that could help as solutions.
Bjarne Stroustrup made a very similar proposal, for very similar
reasons, in "A Standard Adaptor to Support Polymorphic Containers"
(X3J16/96-0030 = WG21/N0848). His proposal was accepted, with minor
modifications, at the Santa Cruz meeting in March '96.
If you have a vector V containing pointers to class Foo, and you want
to apply the member function to all of them, then you'll do something
like this: for_each(V.begin(), V.end(), mem_fun(&Foo::f)).
The adaptor mem_fun takes an argument of type (T::*)() and returns a
function object whose argument type is T*. There are three other such
adaptors: mem_fun_ref takes an argument of type (T::*)() and returns a
function object whose argument type is T&, and mem_fun1 and
mem_fun1_ref do the same thing for member functions that take a single
argument that mem_fun and mem_fun_ref do for member functions that
take no arguments.
--
Matt Austern
SGI: MTI Compilers Group
austern@isolde.mti.sgi.com
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]