版权所有 © 2001, 2002 Peter Dimov 和 Multi Media Ltd.
版权所有 © 2003-2005 Peter Dimov
根据 Boost 软件许可证,版本 1.0 分发。
目录
boost::mem_fn
是标准函数 std::mem_fun
和 std::mem_fun_ref
的泛化。它支持具有多个参数的成员函数指针,并且返回的函数对象可以将指向对象实例的指针、引用或智能指针作为其第一个参数。 mem_fn
还通过将数据成员视为不带参数并返回成员的(const)引用的函数来支持指向数据成员的指针。
mem_fn
的目的有两个。首先,它允许用户使用熟悉的
std::for_each(v.begin(), v.end(), boost::mem_fn(&Shape::draw));
语法对容器调用成员函数,即使容器存储智能指针也是如此。
其次,它可以作为库开发人员的构建块,他们希望将成员函数指针视为函数对象。库可以定义一个增强的 for_each
算法,其重载形式为
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)); }
这将允许使用便捷的语法
for_each(v.begin(), v.end(), &Shape::draw);
在记录该特性时,库作者只需声明
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))
。其中 boost::mem_fn
可以是指向此页面的链接。有关示例,请参阅 bind
的文档。
mem_fn
接受一个参数,一个指向成员的指针,并返回一个适合与标准或用户定义算法一起使用的函数对象
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)); };
返回的函数对象采用与输入成员函数相同的参数,以及一个表示对象实例的“灵活”的第一个参数。
当使用既不是指向相应类(上例中为 X
)的指针也不是引用的第一个参数 x
调用函数对象时,它使用 get_pointer(x)
从 x
获取指针。库作者可以通过提供适当的 get_pointer
重载来“注册”他们的智能指针类,从而允许 mem_fn
识别和支持它们。
[注意: get_pointer
不限于返回指针。任何可以在成员函数调用表达式 (x->*pmf)(...)
中使用的对象都可以工作。]
[注意: 库使用对 get_pointer
的非限定调用。因此,除了任何 boost::get_pointer
重载之外,它还将通过依赖于参数的查找找到在与相应智能指针类相同的命名空间中定义的 get_pointer
重载。]
mem_fn
返回的所有函数对象都公开一个 result_type
typedef,它表示成员函数的返回类型。对于数据成员,result_type
定义为成员的类型。
是的。对于简单用法,mem_fn
提供了标准适配器不具备的附加功能。使用 std::bind1st
、std::bind2nd
或 Boost.Compose 以及标准适配器的复杂表达式可以使用 boost::bind
重写,它会自动利用 mem_fn
。
不,除非您有充分的理由这样做。mem_fn
与标准适配器并非 100% 兼容,尽管它非常接近。特别是,mem_fn
不会像标准适配器那样返回 std::[const_]mem_fun[1][_ref]_t
类型的对象,并且不可能使用标准的 argument_type
和 first_argument_type
嵌套 typedef 完全描述第一个参数的类型。需要可适配函数对象才能运行的库可能不喜欢 mem_fn
。
一般而言,非可移植扩展应默认关闭以防止供应商锁定。如果自动定义了 BOOST_MEM_FN_ENABLE_STDCALL
,您可能会在没有意识到您的代码可能不再可移植的情况下意外地利用它。此外,默认调用约定可能是 __stdcall
,在这种情况下启用 __stdcall
支持将导致重复定义。
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 }
概要中提到的所有未指定-N 类型都是可复制构造的和可赋值的。它们的复制构造函数和赋值运算符不会抛出异常。未指定-N::result_type
定义为作为参数传递给 mem_fn
的成员函数指针的返回类型(概要中的 R
)。未指定-2-1::result_type
定义为 R
。
template<class R, class T> unspecified-1 mem_fn(R (T::*pmf) ())
(t)
等价于 (t.*pmf)()
,当 t
是类型 T
或其派生类型的左值时;否则等价于 (get_pointer(t)->*pmf)()
。template<class R, class T> unspecified-2 mem_fn(R (T::*pmf) () const)
(t)
等价于 (t.*pmf)()
,当 t
是类型 T
[const
] 或其派生类型时;否则等价于 (get_pointer(t)->*pmf)()
。template<class R, class T> unspecified-2-1 mem_fn(R T::*pm)
(t)
等价于 t.*pm
,当 t
是类型 T
[const
] 或其派生类型时;否则等价于 get_pointer(t)->*pm
。template<class R, class T, class A1> unspecified-3 mem_fn(R (T::*pmf) (A1))
(t, a1)
等价于 (t.*pmf)(a1)
,当 t
是类型 T
或其派生类型的左值时;否则等价于 (get_pointer(t)->*pmf)(a1)
。template<class R, class T, class A1> unspecified-4 mem_fn(R (T::*pmf) (A1) const)
(t, a1)
等价于 (t.*pmf)(a1)
,当 t
是类型 T
[const
] 或其派生类型时;否则等价于 (get_pointer(t)->*pmf)(a1)
。template<class R, class T, class A1, class A2> unspecified-5 mem_fn(R (T::*pmf) (A1, A2))
(t, a1, a2)
等价于 (t.*pmf)(a1, a2)
,当 t
是类型 T
或其派生类型的左值时;否则等价于 (get_pointer(t)->*pmf)(a1, a2)
。template<class R, class T, class A1, class A2> unspecified-6 mem_fn(R (T::*pmf) (A1, A2) const)
(t, a1, a2)
等价于 (t.*pmf)(a1, a2)
,当 t
是类型 T
[const
] 或其派生类型时;否则等价于 (get_pointer(t)->*pmf)(a1, a2)
。mem_fn.hpp
使用,请勿直接包含)mem_fn.hpp
使用,请勿直接包含)mem_fn.hpp
使用,请勿直接包含)__fastcall
测试)__stdcall
测试)void
返回值测试)此实现支持最多八个参数的成员函数。这不是设计的固有限制,而是一个实现细节。
一些平台允许多种类型的成员函数,它们的区别在于调用约定(调用函数的规则:如何传递参数,如何处理返回值,以及谁清理堆栈——如果有的话)。
例如,Windows API 函数和 COM 接口成员函数使用一种称为 __stdcall
的调用约定。Borland VCL 组件使用 __fastcall
。UDK,OpenOffice.org 的组件模型,使用 __cdecl
。
要将 mem_fn
与 __stdcall
成员函数一起使用,请在包含 <boost/mem_fn.hpp>
之前#define
宏 BOOST_MEM_FN_ENABLE_STDCALL
。
要将 mem_fn
与 __fastcall
成员函数一起使用,请在包含 <boost/mem_fn.hpp>
之前#define
宏 BOOST_MEM_FN_ENABLE_FASTCALL
。
要将 mem_fn
与 __cdecl
成员函数一起使用,请在包含 <boost/mem_fn.hpp>
之前#define
宏 BOOST_MEM_FN_ENABLE_CDECL
。
最好在项目选项中定义这些宏,通过命令行上的 -D
,或者作为使用 mem_fn
的翻译单元(.cpp 文件)的第一行。 不遵守此规则可能会导致在头文件包含 mem_fn.hpp
之前定义宏时出现模糊错误。
[注意: 这是一个不可移植的扩展。它不是接口的一部分。]
[注意: 一些编译器仅对 __stdcall
关键字提供最低限度的支持。]
mem_fn
适应用户定义的智能指针,这启发了基于 get_pointer
的设计。__stdcall
。bind
和 mem_fn
以支持在缺陷编译器上 void
返回。__cdecl
。此文档已由 Agustín Bergé 移植到 Quickbook。