...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
Copyright © 2001, 2002 Peter Dimov and Multi Media Ltd.
Copyright © 2003-2005 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
Table of Contents
boost::mem_fn
is a generalization of the standard
functions std::mem_fun
and std::mem_fun_ref
.
It supports member function pointers with more than one argument, and the returned
function object can take a pointer, a reference, or a smart pointer to an object
instance as its first argument. mem_fn
also supports pointers to data members by treating them as functions taking
no arguments and returning a (const) reference to the member.
The purpose of mem_fn
is twofold.
First, it allows users to invoke a member function on a container with the
familiar
std::for_each(v.begin(), v.end(), boost::mem_fn(&Shape::draw));
syntax, even when the container stores smart pointers.
Second, it can be used as a building block by library developers that want
to treat a pointer to member function as a function object. A library might
define an enhanced for_each
algorithm with an overload of the form:
template<class It, class R, class T> void for_each(It first, It last, R (T::*pmf) ()) { std::for_each(first, last, boost::mem_fn(pmf)); }
that will allow the convenient syntax:
for_each(v.begin(), v.end(), &Shape::draw);
When documenting the feature, the library author will simply state:
template<class It, class R, class T> void for_each(It first, It last, R (T::*pmf) ());
std::for_each(first, last, boost::mem_fn(pmf))
.
where boost::mem_fn
can be a link to this page. See the
documentation of bind
for an example.
mem_fn
takes one argument,
a pointer to a member, and returns a function object suitable for use with
standard or user-defined algorithms:
struct X { void f(); }; void g(std::vector<X> & v) { std::for_each(v.begin(), v.end(), boost::mem_fn(&X::f)); }; void h(std::vector<X *> const & v) { std::for_each(v.begin(), v.end(), boost::mem_fn(&X::f)); }; void k(std::vector<boost::shared_ptr<X> > const & v) { std::for_each(v.begin(), v.end(), boost::mem_fn(&X::f)); };
The returned function object takes the same arguments as the input member function plus a "flexible" first argument that represents the object instance.
When the function object is invoked with a first argument x
that is neither a pointer nor a reference to the appropriate class (X
in the example above), it uses get_pointer(x)
to obtain
a pointer from x
. Library authors
can "register" their smart pointer classes by supplying an appropriate
get_pointer
overload, allowing
mem_fn
to recognize and support
them.
[Note: get_pointer
is not restricted to return a pointer. Any object that can be used in a member
function call expression (x->*pmf)(...)
will work.]
[Note: the library uses an unqualified call to get_pointer
. Therefore, it will find, through
argument-dependent lookup, get_pointer
overloads that are defined in the same namespace as the corresponding smart
pointer class, in addition to any boost::get_pointer
overloads.]
All function objects returned by mem_fn
expose a result_type
typedef
that represents the return type of the member function. For data members,
result_type
is defined as the
type of the member.
Yes. For simple uses, mem_fn
provides additional functionality that the standard adaptors do not. Complicated
expressions that use std::bind1st
,
std::bind2nd
or Boost.Compose
along with the standard adaptors can be rewritten using boost::bind
that automatically takes advantage of mem_fn
.
No, unless you have good reasons to do so. mem_fn
is not 100% compatible with the standard adaptors, although it comes pretty
close. In particular, mem_fn
does not return objects of type std::[const_]mem_fun[1][_ref]_t
,
as the standard adaptors do, and it is not possible to fully describe the
type of the first argument using the standard argument_type
and first_argument_type
nested
typedefs. Libraries that need adaptable function objects in order to function
might not like mem_fn
.
Non-portable extensions, in general, should default to off to prevent vendor
lock-in. Had BOOST_MEM_FN_ENABLE_STDCALL
been defined automatically, you could have accidentally taken advantage of
it without realizing that your code is, perhaps, no longer portable. In addition,
it is possible for the default calling convention to be __stdcall
,
in which case enabling __stdcall
support will result in duplicate definitions.
namespace boost { template<class T> T *get_pointer
(T * p); template<class R, class T> unspecified-1mem_fn
(R (T::*pmf) ()); template<class R, class T> unspecified-2mem_fn
(R (T::*pmf) () const); template<class R, class T> unspecified-2-1mem_fn
(R T::*pm); template<class R, class T, class A1> unspecified-3mem_fn
(R (T::*pmf) (A1)); template<class R, class T, class A1> unspecified-4mem_fn
(R (T::*pmf) (A1) const); template<class R, class T, class A1, class A2> unspecified-5mem_fn
(R (T::*pmf) (A1, A2)); template<class R, class T, class A1, class A2> unspecified-6mem_fn
(R (T::*pmf) (A1, A2) const); // implementation defined number of additional overloads for more arguments }
All unspecified-N types mentioned in the Synopsis are
CopyConstructible and Assignable.
Their copy constructors and assignment operators do not throw exceptions.
unspecified-N::result_type
is defined as the return type
of the member function pointer passed as an argument to mem_fn
(R
in the Synopsis.) unspecified-2-1::result_type
is defined as R
.
template<class R, class T> unspecified-1 mem_fn(R (T::*pmf) ())
(t)
is equivalent to (t.*pmf)()
when t
is an l-value
of type T
or derived,
(get_pointer(t)->*pmf)()
otherwise.
template<class R, class T> unspecified-2 mem_fn(R (T::*pmf) () const)
(t)
is equivalent to (t.*pmf)()
when t
is of type T
[const
] or derived,
(get_pointer(t)->*pmf)()
otherwise.
template<class R, class T> unspecified-2-1 mem_fn(R T::*pm)
(t)
is equivalent to t.*pm
when t
is of type T
[const
] or derived,
get_pointer(t)->*pm
otherwise.
template<class R, class T, class A1> unspecified-3 mem_fn(R (T::*pmf) (A1))
(t, a1)
is equivalent to (t.*pmf)(a1)
when t
is an l-value
of type T
or derived,
(get_pointer(t)->*pmf)(a1)
otherwise.
template<class R, class T, class A1> unspecified-4 mem_fn(R (T::*pmf) (A1) const)
(t, a1)
is equivalent to (t.*pmf)(a1)
when t
is of type T
[const
] or derived,
(get_pointer(t)->*pmf)(a1)
otherwise.
template<class R, class T, class A1, class A2> unspecified-5 mem_fn(R (T::*pmf) (A1, A2))
(t, a1, a2)
is equivalent to (t.*pmf)(a1, a2)
when t
is an l-value
of type T
or derived,
(get_pointer(t)->*pmf)(a1, a2)
otherwise.
template<class R, class T, class A1, class A2> unspecified-6 mem_fn(R (T::*pmf) (A1, A2) const)
(t, a1, a2)
is equivalent to (t.*pmf)(a1, a2)
when t
is of type T
[const
] or derived,
(get_pointer(t)->*pmf)(a1, a2)
otherwise.
mem_fn.hpp
, do not include directly)
mem_fn.hpp
, do not include directly)
mem_fn.hpp
, do not include directly)
__fastcall
)
__stdcall
)
void
returns)
This implementation supports member functions with up to eight arguments. This is not an inherent limitation of the design, but an implementation detail.
Some platforms allow several types of member functions that differ by their calling convention (the rules by which the function is invoked: how are arguments passed, how is the return value handled, and who cleans up the stack - if any.)
For example, Windows API functions and COM interface member functions use
a calling convention known as __stdcall
.
Borland VCL components use __fastcall
.
UDK, the component model of OpenOffice.org, uses __cdecl
.
To use mem_fn
with __stdcall
member functions, #define
the macro BOOST_MEM_FN_ENABLE_STDCALL
before including <boost/mem_fn.hpp>
.
To use mem_fn
with __fastcall
member functions, #define
the macro BOOST_MEM_FN_ENABLE_FASTCALL
before including <boost/mem_fn.hpp>
.
To use mem_fn
with __cdecl
member functions, #define
the macro BOOST_MEM_FN_ENABLE_CDECL
before including <boost/mem_fn.hpp>
.
It is best to define these macros in the project options,
via -D
on the command line, or as the first line in the translation unit (.cpp file)
where mem_fn
is used.
Not following this rule can lead to obscure errors when a header includes
mem_fn.hpp
before the macro has been defined.
[Note: this is a non-portable extension. It is not part of the interface.]
[Note: Some compilers provide only minimal support for
the __stdcall
keyword.]
mem_fn
adapt to user-defined smart pointers
inspired the get_pointer
-based
design.
__stdcall
.
bind
and mem_fn
to support
void
returns on deficient
compilers.
__cdecl
.
This documentation was ported to Quickbook by Agustín Bergé.