The canonical solution for storing polymorphic objects in standard library
containers is to use a smart pointer such as shared_ptr
[Dimov03a].
Unfortunately, the standard adaptors for pointers to members described in
section 20.3.8 do not support smart pointers.
This document proposes an enhanced member pointer adaptor, mem_fn
,
that
std::mem_fun
and std::mem_fun_ref;
mem_fn
supports the familiar idiom for invoking a member function
on all container elements:
std::for_each(v.begin(), v.end(), mem_fn(&Shape::draw));
The statement works for a container that stores objects, pointers, smart pointers, or iterators.
This flexibility allows components that accept function objects as input to
offer transparent support for pointers to members by using mem_fn
internally
to turn the pointer to member into a function object [Dimov03b].
As an example, consider this hypothetical for_each
overload:
template<class It, class R, class T> void for_each(It first, It last, R T::* pm) { std::for_each(first, last, mem_fn(pm)); }
Scott Meyers remarks in [Meyers01] that
In a perfect world, I'd also be able to use
for_each
to invokeWidget::test
on each object invw
:for_each(vw.begin(), vw.end(), &Widget::test); // Call #2 (won't compile)In fact, if the world were really perfect, I'd be able to use
for_each
to invokeWidget::test
on a container ofWidget*
pointers, too:list<Widget*> lpw; // lpw holds pointers to widgets for_each(lpw.begin(), lpw.end(), &Widget::test); // Call #3 (also won't compile)
This is exactly the functionality offered by the above for_each
overload.
The hypothetical proposed text for our enhanced for_each
can reuse
the mem_fn
specification as well:
template<class It, class R, class T> void for_each(It first, It last, R T::* pm);Effects: equivalent to
std::for_each(first, last, mem_fn(pm));
This proposal is almost a pure library extension. It proposes changes to an
existing header, <functional>
, but it does not require
changes to any standard classes or functions and it does not require changes to
any of the standard requirement tables. It does not require any changes in the
core language, and it has been implemented in standard C++ [Boost01].
The proposal does not depend on any other library extensions.
std::mem_fun
ExtensionThis proposal introduces a new function template mem_fn
and does
not propose changes to the existing function template std::mem_fun
in order to not impact existing code, as the return type of std::mem_fun
is specified by the standard.
The function objects returned by mem_fn
can take either an object
pointer or an object reference as its first argument. This allows components
that automatically recognize pointers to members, transparently wrapping them
with mem_fn
, to accept pointers and references. As the wrapping is
done implicitly, the user has no way to specify one or the other.
The return type of mem_fn
is not specified by this proposal, as it
is rarely needed, and can reflect implementation details. The Boost
implementation does not specify the return type of mem_fn
, and
there have been no complaints from users.
get_pointer(t)->*pm
vs ( *t).*pm
When the argument is not an object reference, the Boost implementation uses an
unqualified call to get_pointer
to obtain a pointer from the
argument, and the ->*
operator to perform the call. This
proposal dereferences the argument instead, using the .*
operator
for the call. This allows mem_fn
to support most smart pointers
and iterators "out of the box", without requiring explicit support in the form
of a get_pointer
overload.
result_type
for data membersThe return type of mem_fn(&X::f)
, where f
is a
member function of X
, is always the same as the return type of f
.
The return type of mem_fn(&X::m)
, where m
is a
data member of X
of type M
, can vary depending on M
and the cv-qualification of the object identified by the first argument of the
call. When M
is a reference type, the return type is M
;
otherwise, the return type is a reference to (possibly cv-qualified) M
.
In this proposal, implementations are allowed to define the result_type
of the function object returned by mem_fn(&X::m)
as either M
or M const &
. It is not possible to express the exact return
type in a single typedef, and neither M
nor M const &
is inherently a better choice.
template<class R, class T> unspecified mem_fn(R T::* pm);
mem_fn(&X::f)
, where f
is a member function of X
,
returns an object through which &X::f
can be called given a
pointer, a smart pointer, an iterator, or a reference to X
followed
by the argument list required for X::f
, if any. The returned
object is CopyConstructible
, Assignable
, its copy
constructor and assignment operator do not throw exceptions, and it has a
nested typedef result_type
defined as the return type of
f
.
mem_fn(&X::m)
, where m
is a data member of X
,
returns an object through which a reference to &X::m
can be
obtained given a pointer, a smart pointer, an iterator, or a reference to X
.
The returned object is CopyConstructible
, Assignable
,
its copy constructor and assignment operator do not throw exceptions, and it
has a nested typedef result_type
defined as either M
or M const &
where M
is the type of m
.
template<class R, class T> unspecified mem_fn(R T::* pm);
Returns:
pm
is a pointer to a member function taking n
arguments,
a function object f
such that the expression f(t, a1,
..., an)
is equivalent to (t.*pm)(a1, ..., an)
when t
is an lvalue of type T
or derived from T
,
((*t).*pm)(a1, ..., an)
otherwise.
pm
is a pointer to a data member, a function object f
such that the expression f(t)
is equivalent to t.*pm
when
t
is an lvalue of type T
or derived from T
,
(*t).*pm
otherwise.Throws: nothing.
Notes: Implementations are allowed to impose an upper limit on n
.
Implementations are allowed to implement mem_fn
as a set of
overloaded function templates.
[Boost01] Boost mem_fn library documentation, September 2001. Available online at http://www.boost.org/libs/mem_fn/
[Dimov03a] Peter Dimov, Beman Dawes, Greg Colvin, A Proposal to Add General Purpose Smart Pointers to the Library Technical Report, C++ committee document N1431=03-0013, February 2003. Available online at http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1431.htm
[Dimov03b] Peter Dimov, Douglas Gregor, Jaakko Järvi, Gary Powell, A Proposal to Add an Enhanced Binder to the Library Technical Report, C++ committee document N1438=03-0020, February 2003. Available online at http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1438.htm
[Meyers01] Scott Meyers, Effective STL, Item 41, page 174, Addison-Wesley, June 2001, ISBN 0-201-74962-9.