mem_fn.hpp |
|
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:
Effects: equivalent to 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.
Yes, if you #define BOOST_MEM_FN_ENABLE_STDCALL.
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-1 mem_fn(R (T::*pmf) ()); template<class R, class T> unspecified-2 mem_fn(R (T::*pmf) () const); template<class R, class T> unspecified-2-1 mem_fn(R T::*pm); template<class R, class T, class A1> unspecified-3 mem_fn(R (T::*pmf) (A1)); template<class R, class T, class A1> unspecified-4 mem_fn(R (T::*pmf) (A1) const); template<class R, class T, class A1, class A2> unspecified-5 mem_fn(R (T::*pmf) (A1, A2)); template<class R, class T, class A1, class A2> unspecified-6 mem_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.
Returns: p.
Throws: Nothing.
Returns: a function object f such that the expression f(t) is equivalent to (t.*pmf)() when t is an l-value of type T or derived, (get_pointer(t)->*pmf)() otherwise.
Throws: Nothing.
Returns: a function object f such that the expression f(t) is equivalent to (t.*pmf)() when t is of type T [const] or derived, (get_pointer(t)->*pmf)() otherwise.
Throws: Nothing.
Returns: a function object f such that the expression f(t) is equivalent to t.*pm when t is of type T [const] or derived, get_pointer(t)->*pm otherwise.
Throws: Nothing.
Returns: a function object f such that the expression f(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.
Throws: Nothing.
Returns: a function object f such that the expression f(t, a1) is equivalent to (t.*pmf)(a1) when t is of type T [const] or derived, (get_pointer(t)->*pmf)(a1) otherwise.
Throws: Nothing.
Returns: a function object f such that the expression f(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.
Throws: Nothing.
Returns: a function object f such that the expression f(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.
Throws: Nothing.
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, directly or indirectly, <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.]
Rene Jager's initial suggestion of using traits classes to make mem_fn adapt to user-defined smart pointers inspired the get_pointer-based design.
Numerous improvements were suggested during the formal review period by Richard Crossley, Jens Maurer, Ed Brey, and others. Review manager was Darin Adler.
Steve Anichini pointed out that COM interfaces use __stdcall.
Dave Abrahams modified bind and mem_fn to support void returns on deficient compilers.
Daniel Boelzle pointed out that UDK uses __cdecl.
Copyright © 2001, 2002 by Peter Dimov and Multi Media Ltd. Copyright 2003-2005 Peter Dimov. Permission
to copy, use, modify, sell and distribute this document is granted provided
this copyright notice appears in all copies. This document is provided "as is"
without express or implied warranty, and with no claim as to its suitability
for any purpose.