bind.hpp | |
Contents
目的
和函数及函数指针一起使用 bind
和函数对象一起使用 bind
和成员指针一起使用 bind
为函数组合使用嵌套的 binds
重载操作符
示例
和标准算法一起使用 bind
和 Boost.Function 一起使用 bind
局限性
常见问题
这个为什么不能编译?
这个为什么能编译?它应该不能。
bind(f, ...) 和 bind<R>(f, ...) 有什么不同?
bind 可以和 Windows API 函数一起工作吗?
bind 可以和 COM 方法一起工作吗?
bind 可以和 Mac 工具箱函数一起工作吗?
bind 可以和 extern "C" 函数一起工作吗?
bind 为什么不能自动识别非标准函数?
故障诊断
错误的参数数量
函数对象不能被指定的参数调用
访问一个不存在的参数
bind(f, ...) 的不恰当使用
bind<R>(f, ...) 的不恰当使用
绑定一个非标准函数
绑定一个被重载的函数
识别标识中的 const
MSVC 特有:using boost::bind;
MSVC 特有:类模板遮盖函数模板
MSVC 特有:将识别标识中的 ... 看作类型
接口
概要
共通需求
共通定义
bind
补充重载
实现
文件
相关内容
参数数量
"__stdcall", "__cdecl", "__fastcall", 和 "pascal" 支持
visit_each 支持
感谢
Purpose(目的)
boost::bind 是标准函数 std::bind1st 和 std::bind2nd 的泛化。它支持任意的函数对象,函数,函数指针,和成员函数指针,它还能将任何参数绑定为一个特定的值,或者将输入的参数发送到任意的位置。bind 对函数对象没有任何要求,特别是,它不需要 result_type,first_argument_type 和 second_argument_type 这样的标准 typedefs。
Using bind with functions and function pointers(和函数及函数指针一起使用 bind)
给定这些定义:
int f(int a, int b) { return a + b; } int g(int a, int b, int c) { return a + b + c; }
bind(f, 1, 2) 会产生一个“无元”函数对象,它不需要参数并返回 f(1, 2)。同样,bind(g, 1, 2, 3)() 等价于 g(1, 2, 3)。
有选择性地只绑定一部分参数也是有可能的。bind(f, _1, 5)(x) 等价于 f(x, 5),这里,_1 是一个占位符参数,它的含义是“用第一个输入参数取代”。
作为对照,这是用标准库原始形式表达的同样操作:
std::bind2nd(std::ptr_fun(f), 5)(x);
bind 同样覆盖了 std::bind1st 的功能:
std::bind1st(std::ptr_fun(f), 5)(x); // f(5, x) bind(f, 5, _1)(x); // f(5, x)
bind 能够处理带有两个以上参数的函数,而且它的参数取代机制更为直观:
bind(f, _2, _1)(x, y); // f(y, x) bind(g, _1, 9, _1)(x); // g(x, 9, x) bind(g, _3, _3, _3)(x, y, z); // g(z, z, z) bind(g, _1, _1, _1)(x, y, z); // g(x, x, x)
注意,最后一个示例中,由 bind(g, _1, _1, _1) 生成的函数对象不包含对第一个参数以外的任何参数的引用,但是它仍然能使用一个以上的参数。所有多余的参数被悄悄地忽略,就像在第三个示例中,第一和第二个参数被忽略。
bind 持有的参数被返回的函数对象拷贝并内部持有。例如,在下面的代码中:
int i = 5; bind(f, i, _1);
一个 i 的值的拷贝被存储于函数对象中。boost::ref 和 boost::cref 可用于让函数对象存储一个引用而不是拷贝:
int i = 5; bind(f, ref(i), _1); bind(f, cref(42), _1);
Using bind with function objects(和函数对象一起使用 bind)
bind 并不限于函数,它可以接受任何函数对象。通常情况下,生成的函数对象的 operator() 的返回类型必须显式指定(没有 typeof 操作符,返回类型无法推导):
struct F { int operator()(int a, int b) { return a - b; } bool operator()(long a, long b) { return a == b; } }; F f; int x = 104; bind<int>(f, _1, _1)(x); // f(x, x), i.e. zero
有些编译器遇到 bind<R>(f, ...) 语法会发生问题。出于可移植性的原因,一种和上面的意思相同的可选的表达方式也被支持:
boost::bind(boost::type<int>(), f, _1, _1)(x);
但是要注意,这种可选语法只是作为一个 workaround 提供。它不是接口的一部分。
当函数对象暴露了一个名为 result_type 的内嵌类型时,显式返回类型可以被省略:
int x = 8; bind(std::less<int>(), _1, 9)(x); // x < 9
【注意:这种省略返回类型的能力并非在所有的编译器上都可用。】
缺省情况下,bind 为提供的函数对象做出一份拷贝。boost::ref
和 boost::cref
可用于让它存储这个函数对象的引用,而非拷贝。当函数对象是不可拷贝的,拷贝代价高昂,或者包含状态时是很有用的,当然,在这种情况下,要求程序员确保这个函数对象在使用期间不能被销毁。
struct F2 { int s; typedef void result_type; void operator()( int x ) { s += x; } }; F2 f2 = { 0 }; int a[] = { 1, 2, 3 }; std::for_each( a, a+3, bind( ref(f2), _1 ) ); assert( f2.s == 6 );
Using bind with pointers to members(和成员指针一起使用 bind)
成员函数的指针和数据成员的指针不是函数对象,因为它们不支持 operator()。为了方便起见,bind 接受成员指针作为它的第一个参数,而它的行为就像使用 boost::mem_fn 将成员指针转换成一个函数对象一样。换句话说,当 R 是 X::f 的返回类型(作为成员函数)或成员本身的类型(作为数据成员)时,表达式
bind(&X::f, args)
与
bind<R>(mem_fn(&X::f), args)
等价。
【注意:mem_fn 创建的函数对象可以接受一个对象的指针,引用或智能指针作为它的第一个参数,更多的信息,参见 mem_fn 文档。】
示例:
struct X { bool f(int a); }; X x; shared_ptr<X> p(new X); int i = 5; bind(&X::f, ref(x), _1)(i); // x.f(i) bind(&X::f, &x, _1)(i); //(&x)->f(i) bind(&X::f, x, _1)(i); // (internal copy of x).f(i) bind(&X::f, p, _1)(i); // (internal copy of p)->f(i)
最后两个示例的有趣之处在于它们生成“自包含”的函数对象。bind(&X::f, x, _1) 存储 x 的一个拷贝。bind(&X::f, p, _1) 存储 p 的一个拷贝,而且因为 p 是一个 boost::shared_ptr,这个函数对象保存一个属于它自己的 X 的实例的引用,而且当 p 离开它的作用域或者被 reset() 之后,这个引用依然保持有效。
Using nested binds for function composition(为函数组合使用嵌套的 binds)
传给 bind 的某些参数可以嵌套 bind 表达式自身:
bind(f, bind(g, _1))(x); // f(g(x))
当函数对象被调用的时候,如果没有指定顺序,内部 bind 表达式先于外部 bind 表达式被求值,在外部 bind 表达式被求值的时候,用内部表达式的求值结果取代它们的占位符的位置。在上面的示例中,当用参数列表 (x) 调用那个函数对象的时候,bind(g, _1)(x) 首先被求值,生成 g(x),然后 bind(f, g(x))(x) 被求值,生成最终结果 f(g(x))。
bind 的这个特性可被用来执行函数组合。参见示例 bind_as_compose.cpp,示范如何用 bind 达到与 Boost.Compose 类似的功能。
注意第一个参数——被绑定函数对象——是不被求值的,即使它是一个由 bind 生成的函数对象或一个占位符参数,所以下面的示例不会如你所愿地工作:
typedef void (*pf)(int); std::vector<pf> v; std::for_each(v.begin(), v.end(), bind(_1, 5));
你所要的效果,可以通过将一个辅助函数对象 apply 用作它的第一个参数而获得,作为一个函数对象,它可以支撑它的参数列表。为了方便起见,在 boost/bind/apply.hpp 头文件中提供了一个 apply 的实现。下面是一个前面的示例的修改版本:
typedef void (*pf)(int); std::vector<pf> v; std::for_each(v.begin(), v.end(), bind(apply<void>(), _1, 5));
尽管在缺省情况下,第一个参数是不被求值的,而所有其它参数被求值。但有时候不需要对第一个参数之后的其它参数求值,甚至当它们是内嵌 bind 子表达式的时候也不需要。这可以由另一个函数对象 protect 来帮助做到,它将类型掩饰起来,让 bind 无法对它进行识别和求值。在被调用的时候,protect 只是简单地不加更改地将参数列表转送到其它函数对象中。
头文件 boost/bind/protect.hpp 包含一个 protect 的实现。要在求值中保护一个 bind 函数对象,使用 protect(bind(f, ...))。
Overloaded operators (new in Boost 1.33)(重载的操作符(Boost 1.33 新增))
为了方便起见,由 bind 生成的函数对象重载了 logical not(逻辑非)操作符 !
和关系操作符 ==
, !=
, <
, <=
, >
, >=
, &&
, ||
。
如果 logical_not 是一个持有一个参数 x 并返回 !x 的函数对象,则 !bind(f, ...) 等价于 bind( logical_not(), bind(f, ...) )。
如果 op 是一个关系或逻辑操作符,并且 relation 是一个持有两个参数 a 和 b 并返回 a op b 的函数对象,则 bind(f, ...) op x 等价于 bind( relation(), bind(f, ...), x )。
这实际上意味着你可以方便地对 bind 的结果求非:
std::remove_if( first, last, !bind( &X::visible, _1 ) ); // remove invisible objects
以及方便地将 bind 的结果和一个值进行比较:
std::find_if( first, last, bind( &X::name, _1 ) == "Peter" );
std::find_if( first, last, bind( &X::name, _1 ) == "Peter" || bind( &X::name, _1 ) == "Paul" );
和一个占位符进行比较:
bind( &X::name, _1 ) == _2
或者和另一个 bind 表达式进行比较:
std::sort( first, last, bind( &X::name, _1 ) < bind( &X::name, _2 ) ); // sort by name
Examples(示例)
Using bind with standard algorithms(和标准算法一起使用 bind)
class image; class animation { public: void advance(int ms); bool inactive() const; void render(image & target) const; }; std::vector<animation> anims; template<class C, class P> void erase_if(C & c, P pred) { c.erase(std::remove_if(c.begin(), c.end(), pred), c.end()); } void update(int ms) { std::for_each(anims.begin(), anims.end(), boost::bind(&animation::advance, _1, ms)); erase_if(anims, boost::mem_fn(&animation::inactive)); } void render(image & target) { std::for_each(anims.begin(), anims.end(), boost::bind(&animation::render, _1, boost::ref(target))); }
Using bind with Boost.Function(和 Boost.Function 一起使用 bind)
class button { public: boost::function<void()> onClick; }; class player { public: void play(); void stop(); }; button playButton, stopButton; player thePlayer; void connect() { playButton.onClick = boost::bind(&player::play, &thePlayer); stopButton.onClick = boost::bind(&player::stop, &thePlayer); }
Limitations(局限性)
作为一个通用规则,由 bind 生成的函数对象以引用方式持有它们的参数,因此,不能接受非 const 临时对象或字面常量。这是 C++ 语言的当前(2003)版本与生俱来的局限,称为 the forwarding problem。(它将在下一版标准(通常称为 C++0x)中被修正。)
这个库以下面这种形式的识别标识
template<class T> void f(T & t);
接受任意类型的参数并将它们不加改变地传递。注意,这不能用于非 const 右值。
在支持函数模板部分排序的编译器上,一个可能的解决方案是增加一个重载:
template<class T> void f(T & t); template<class T> void f(T const & t);
很不幸,对于 9 个参数,这样需要提供 512 个重载,这是不切实际的。这个库选择了一个小的子集:对于不大于两个参数的情况,完整地提供了常量重载,对于三个及更多参数,它为所有参数都以常引用方式持有的情况提供了单一的补充重载。这覆盖了使用情况的一个合理的部分。
Frequently Asked Questions(常见问题)
Why doesn't this compile?(这个为什么不能编译?)
参见专门的 Troubleshooting(故障诊断)部分。
Why does this compile? It should not.(这个为什么能编译?它应该不能。)
Probably because you used the general bind<R>(f, ...) syntax,
也许是因为你使用了通用的 bind<R>(f, ...) 语法,从而指示 bind 不需要“检查” f 以查明参数数量和返回类型的错误。
What is the difference between bind(f, ...) and bind<R>(f, ...)?(bind(f, ...) 和 bind<R>(f, ...) 有什么不同?)
第一个形式指示 bind 去检查 f 的类型以确定它的 arity(参数数量)和返回类型。参数数量错误将在“绑定时间”查明。当然,这样的语法对 f 有一定的要求。它必须是一个函数,函数指针,成员函数指针,或定义了一个内嵌的名为 result_type 的类型的函数对象,简而言之,它必须是某种 bind 可以识别的东西。
第二个形式指示 bind 不要试图识别 f 的类型。它通常和那些没有或不能暴露 result_type 的函数对象一起使用,但是它也能和非标准函数一起使用。例如,当前实现不能自动识别像 printf 这样的可变参数函数,所以你必须用 bind<int>(printf, ...)。注意,有一种可选的 bind(type<R>(), f, ...) 语法因为可移植性的原因也被支持。
另一个需要考虑的重要因素是:当 f 是一个函数对象时,不支持模板偏特化或函数模板部分排序的编译器不能处理第一种形式,而且,大部分情况下,当 f 是一个函数(指针)或成员函数指针时,不能处理第二种形式。
Does bind work with Windows API functions?(bind 可以和 Windows API 函数一起工作吗?)
可以,只要你 #define BOOST_BIND_ENABLE_STDCALL。另一个可选方法是将这个函数看成一个一般函数对象并使用 bind<R>(f, ...) 语法。
Does bind work with COM methods?(bind 可以和 COM 方法一起工作吗?)
可以,只要你 #define BOOST_MEM_FN_ENABLE_STDCALL。
Does bind work with Mac toolbox functions?
可以,只要你 #define BOOST_BIND_ENABLE_PASCAL。另一个可选方法是将这个函数看成一个一般函数对象并使用 bind<R>(f, ...) 语法。
Does bind work with extern "C" functions?(bind 可以和 extern "C" 函数一起工作吗?)
有时可以。在一些平台上,extern "C" 函数指针等价于“一般的”函数指针,所以它们能很好地工作。另一些平台将它们看做不同的类型。期待一个平台相关的 bind 实现显然可以解决问题,但这个实现不行。照例,workaround 将这个函数看成一个一般函数对象并使用 bind<R>(f, ...) 语法。
Why doesn't bind automatically recognize nonstandard functions?(bind 为什么不能自动识别非标准函数?)
一般而言,不可移植扩展在默认状态下应该关闭,以预防被厂商锁定。如果适当的宏被自动定义,你可能无意中使用了它而并不确定你的代码也许不能再移植。另外,有些编译器有选项让 __stdcall (__fastcall) 成为它们缺省的调用约定,在这种情况下,就不再需要个别的支持。
Troubleshooting(故障诊断)
Incorrect number of arguments(错误的参数数量)
在表达式 bind(f, a1, a2, ..., aN) 中,函数对象 f 必须能够持有正好 N 个参数。这个错误通常在“绑定时间”被查出。换句话说,这个编译错误会被报告在 bind() 被调用的那一行:
int f(int, int); int main() { boost::bind(f, 1); // error, f takes two arguments boost::bind(f, 1, 2); // OK }
这个错误的一个常见变化是忘记成员函数有一个隐含的 "this" 参数:
struct X { int f(int); } int main() { boost::bind(&X::f, 1); // error, X::f takes two arguments boost::bind(&X::f, _1, 1); // OK }
The function object cannot be called with the specified arguments(函数对象不能被指定的参数调用)
和通常的函数调用一样,被绑定的函数对象必须和参数列表一致。这种不一致通常在“调用时间”被编译器检测出来,而结果通常是在 bind.hpp 中类似下面这样的一行中的错误:
return f(a[a1_], a[a2_]);
这种错误的一个示例如下:
int f(int); int main() { boost::bind(f, "incompatible"); // OK so far, no call boost::bind(f, "incompatible")(); // error, "incompatible" is not an int boost::bind(f, _1); // OK boost::bind(f, _1)("incompatible"); // error, "incompatible" is not an int }
Accessing an argument that does not exist(访问一个不存在的参数)
占位符 _N 选择在“调用时间”被传递的参数列表的第 N 个参数。很自然,这是一个试图访问超出这个列表的末尾的错误:
int f(int); int main() { boost::bind(f, _1); // OK boost::bind(f, _1)(); // error, there is no argument number 1 }
这个错误通常被报告在 bind.hpp 中,类似下面这样的一行中:
return f(a[a1_]);
一个常见的这类错误是在模仿 std::bind1st(f, a) 时,键入 bind(f, a, _2),而不是正确的 bind(f, a, _1)。
Inappropriate use of bind(f, ...)(bind(f, ...) 的不恰当使用)
bind(f, a1, a2, ..., aN) 形式引起对 f 的类型的自动检测。它不能和任意的函数对象一起工作,f 必须是一个函数或成员函数指针。
定义了 result_type 的函数对象使用这种形式也是允许的,但是只有在编译器支持偏特化和部分排序的時候才可以。特別是,MSVC 直到版本 7.0 还不支持函数对象的这种语法。
Inappropriate use of bind<R>(f, ...)(bind<R>(f, ...) 的不恰当使用)
bind<R>(f, a1, a2, ..., aN) 形式支持任意函数对象。
将这种形式用于函数或成员函数指针也是允许的(但不推荐),但是只有在编译器支持部分排序时才行。特别是,MSVC 直到版本 7.0 还不完全支持函数和成员函数指针的这种语法。
Binding a nonstandard function(绑定一个非标准函数)
缺省情况下,bind(f, a1, a2, ..., aN) 形式识别“一般的”C++ 函数和函数指针。使用不同的调用约定的函数或像 std::printf 这样的可变参数函数不能工作。通用的 bind<R>(f, a1, a2, ..., aN) 形式和非标准函数一起工作。
在一些平台上,extern "C" 函数,比如 std::strcmp 不能被短形式的 bind 识别。
Binding an overloaded function(绑定一个被重载的函数)
绑定一个被重载的函数的企图通常对导致一个错误,因为无法表示到底要绑定哪一个重载版本。对于带有 const 和非 const 两个重载的成员函数来说,这是一个很常见的问题,就像这个简化的示例:
struct X { int& get(); int const& get() const; }; int main() { boost::bind( &X::get, _1 ); }
这里的二义性可以通过将(成员)函数指针强制转换到想要的类型来解决:
int main() { boost::bind( static_cast< int const& (X::*) () const >( &X::get ), _1 ); }
另一个或许更可读的办法是引入一个临时变量:
int main() { int const& (X::*get) () const = &X::get; boost::bind( get, _1 ); }
const in signatures(识别标识中的 const)
有些编译器,包括 MSVC 6.0 和 Borland C++ 5.5.1,处理函数识别标识中的顶层 const 存在问题:
int f(int const); int main() { boost::bind(f, 1); // error }
workaround:从参数中移除 const 修饰符。
MSVC specific: using boost::bind;(MSVC 特有:using boost::bind;)
在 MSVC(直到版本 7.0)上,当 boost::bind 是由一个 using 声明:
using boost::bind;
带入当前作用域的时候,语法 bind<R>(f, ...) 不能工作。workaround:使用被限定的名字,boost::bind,或者用 using 指令代替:
using namespace boost;
MSVC specific: class templates shadow function templates(MSVC 特有:类模板遮盖函数模板)
在 MSVC(直到版本 7.0)上,一个内嵌的名为 bind 的类模板会遮盖函数模板 boost::bind,破坏了 bind<R>(f, ...) 语法。很不幸,某些库包含内嵌的名为 bind 的类模板(讽刺的是,这些代码常常是某个 MSVC 特有的 workaround)。
workaround 是使用可选的 bind(type<R>(), f, ...) 语法。
MSVC specific: ... in signatures treated as type(MSVC 特有:将识别标识中的 ... 看作类型)
在 MSVC(直到版本 7.0)将可变参数函数(比如 std::printf)中的省略号看作一个类型。因此,它会接受(在当前实现中是错误的)形式:
bind(printf, "%s\n", _1);
并会拒绝正确版本:
bind<int>(printf, "%s\n", _1);
Interface(接口)
Synopsis(概要)
namespace boost { // no arguments template<class R, class F> unspecified-1 bind(F f); template<class F> unspecified-1-1 bind(F f); template<class R> unspecified-2 bind(R (*f) ()); // one argument template<class R, class F, class A1> unspecified-3 bind(F f, A1 a1); template<class F, class A1> unspecified-3-1 bind(F f, A1 a1); template<class R, class B1, class A1> unspecified-4 bind(R (*f) (B1), A1 a1); template<class R, class T, class A1> unspecified-5 bind(R (T::*f) (), A1 a1); template<class R, class T, class A1> unspecified-6 bind(R (T::*f) () const, A1 a1); template<class R, class T, class A1> unspecified-6-1 bind(R T::*f, A1 a1); // two arguments template<class R, class F, class A1, class A2> unspecified-7 bind(F f, A1 a1, A2 a2); template<class F, class A1, class A2> unspecified-7-1 bind(F f, A1 a1, A2 a2); template<class R, class B1, class B2, class A1, class A2> unspecified-8 bind(R (*f) (B1, B2), A1 a1, A2 a2); template<class R, class T, class B1, class A1, class A2> unspecified-9 bind(R (T::*f) (B1), A1 a1, A2 a2); template<class R, class T, class B1, class A1, class A2> unspecified-10 bind(R (T::*f) (B1) const, A1 a1, A2 a2); // implementation defined number of additional overloads for more arguments } namespace { unspecified-placeholder-type-1 _1; unspecified-placeholder-type-2 _2; unspecified-placeholder-type-3 _3; // implementation defined number of additional placeholder definitions }
Common requirements(共通需求)
所有由 bind 返回的 unspecified-N 类型都是 CopyConstructible(可拷贝构造)的。unspecified-N::result_type 被定义为 unspecified-N::operator() 的返回类型。
所有 unspecified-placeholder-N 都是 CopyConstructible(可拷贝构造)的。它们的拷贝构造函数不会抛出异常。
Common definitions(共通定义)
当 m 是一个非负整数时,函数 µ(x, v1, v2, ..., vm) 被定义为:
- 当 x 是某个类型 T 的 boost::reference_wrapper<T> 类型时,x.get()。
- 当 x 是某个正整数 k 的占位符 _k(或它的一个拷贝)时,vk。
- 当 x 是 bind 返回的一个函数对象(或它的一个拷贝)时,x(v1, v2, ..., vm)。
- 否则,x。
bind
template<class R, class F> unspecified-1 bind(F f)
返回:一个使得表达式 λ(v1, v2, ..., vm) 等价于 f() 的函数对象 λ,隐式转换为 R。
抛出:不抛出异常,除非 F 的拷贝构造函数抛出异常。
template<class F> unspecified-1-1 bind(F f)
效果:等价于 bind<typename F::result_type, F>(f);
注意:作为一种扩展,实现允许通过其它手段推断 f 的返回类型,而不依赖于 result_type 成员。
template<class R> unspecified-2 bind(R (*f) ())
返回:一个使得表达式 λ(v1, v2, ..., vm) 等价于 f() 的函数对象 λ。
抛出:不抛出异常。
template<class R, class F, class A1> unspecified-3 bind(F f, A1 a1)
返回:一个使得表达式 λ(v1, v2, ..., vm) 等价于 f(µ(a1, v1, v2, ..., vm)) 的函数对象 λ,隐式转换为 R。
抛出:不抛出异常,除非 F 或 A1 的拷贝构造函数抛出异常。
template<class F, class A1> unspecified-3-1 bind(F f, A1 a1)
效果:等价于 bind<typename F::result_type, F, A1>(f, a1);
注意:作为一种扩展,实现允许通过其它手段推断 f 的返回类型,而不依赖于 result_type 成员。
template<class R, class B1, class A1> unspecified-4 bind(R (*f) (B1), A1 a1)
返回:一个使得表达式 λ(v1, v2, ..., vm) 等价于 f(µ(a1, v1, v2, ..., vm)) 的函数对象 λ。
抛出:不抛出异常,除非 A1 的拷贝构造函数抛出异常。
template<class R, class T, class A1> unspecified-5 bind(R (T::*f) (), A1 a1)
效果:等价于 bind<R>(boost::mem_fn(f), a1);
template<class R, class T, class A1> unspecified-6 bind(R (T::*f) () const, A1 a1)
效果:等价于 bind<R>(boost::mem_fn(f), a1);
template<class R, class T, class A1> unspecified-6-1 bind(R T::*f, A1 a1)
效果:等价于 bind<R>(boost::mem_fn(f), a1);
template<class R, class F, class A1, class A2> unspecified-7 bind(F f, A1 a1, A2 a2)
返回:一个使得表达式 λ(v1, v2, ..., vm) 等价于 f(µ(a1, v1, v2, ..., vm), µ(a2, v1, v2, ..., vm)) 的函数对象 λ,隐式转换为 R。
抛出:不抛出异常,除非 F,A1 或 A2 的拷贝构造函数抛出异常。
template<class F, class A1, class A2> unspecified-7-1 bind(F f, A1 a1, A2 a2)
效果:等价于 bind<typename F::result_type, F, A1, A2>(f, a1, a2);
注意:作为一种扩展,实现允许通过其它手段推断 f 的返回类型,而不依赖于 result_type 成员。
template<class R, class B1, class B2, class A1, class A2> unspecified-8 bind(R (*f) (B1, B2), A1 a1, A2 a2)
返回:一个使得表达式 λ(v1, v2, ..., vm) 等价于 f(µ(a1, v1, v2, ..., vm), µ(a2, v1, v2, ..., vm)) 的函数对象 λ。
抛出:不抛出异常,除非 A1 或 A2 的拷贝构造函数抛出异常。
template<class R, class T, class B1, class A1, class A2> unspecified-9 bind(R (T::*f) (B1), A1 a1, A2 a2)
效果:等价于 bind<R>(boost::mem_fn(f), a1, a2);
template<class R, class T, class B1, class A1, class A2> unspecified-10 bind(R (T::*f) (B1) const, A1 a1, A2 a2)
效果:等价于 bind<R>(boost::mem_fn(f), a1, a2);
Additional overloads(补充重载)
实现允许提供补充的 bind 重载以支持更多的参数或不同的函数指针变种。
Implementation(实现)
Files(文件)
- boost/bind.hpp(主头文件)
- boost/bind/bind_cc.hpp(供 bind.hpp 使用,不直接包含)
- boost/bind/bind_mf_cc.hpp(供 bind.hpp 使用,不直接包含)
- boost/bind/bind_template.hpp(供 bind.hpp 使用,不直接包含)
- boost/bind/arg.hpp(定义占位符参数的类型)
- boost/bind/placeholders.hpp(定义 _1, _2, ... _9 占位符)
- boost/bind/apply.hpp(apply 辅助函数对象)
- boost/bind/protect.hpp(protect 辅助函数)
- boost/bind/make_adaptable.hpp(make_adaptable 辅助函数)
- libs/bind/test/bind_test.cpp(测试)
- libs/bind/bind_as_compose.cpp(函数组合示例)
- libs/bind/bind_visitor.cpp(visitor 示例)
- libs/bind/test/bind_stdcall_test.cpp(带有 __stdcall 的函数的测试)
- libs/bind/test/bind_stdcall_mf_test.cpp(带有 __stdcall 的成员函数的测试)
- libs/bind/test/bind_fastcall_test.cpp(带有 __fastcall 的函数的测试)
- libs/bind/test/bind_fastcall_mf_test.cpp(带有 __fastcall 的成员函数的测试)
Dependencies(相关内容)
Number of Arguments(参数数量)
这个实现支持最多 9 个参数的函数对象。这是一个实现细节,不是设计的固有限制。
"__stdcall", "__cdecl", "__fastcall", and "pascal" Support("__stdcall", "__cdecl", "__fastcall", 和 "pascal" 支持)
有些平台允许通过调用约定(函数被调用时的规则:参数如何传递,返回值如何处理,谁来清理栈(如果有的话))来区分(成员)函数的若干类型。
例如,Windows API 函数和 COM 接口成员函数使用一种名为 __stdcall 的调用约定。Borland VCL 组件使用 __fastcall。Mac 工具箱函数使用一种 pascal 调用约定。
为了和 __stdcall 函数一起使用 bind,在包含 <boost/bind.hpp> 之前 #define 宏 BOOST_BIND_ENABLE_STDCALL。
为了和 __stdcall 成员函数一起使用 bind,在包含 <boost/bind.hpp> 之前 #define 宏 BOOST_MEM_FN_ENABLE_STDCALL。
为了和 __fastcall 函数一起使用 bind,在包含 <boost/bind.hpp> 之前 #define 宏 BOOST_BIND_ENABLE_FASTCALL。
为了和 __fastcall 成员函数一起使用 bind,在包含 <boost/bind.hpp> 之前 #define 宏 BOOST_MEM_FN_ENABLE_FASTCALL。
为了和 pascal 函数一起使用 bind,在包含 <boost/bind.hpp> 之前 #define 宏 BOOST_BIND_ENABLE_PASCAL。
为了和 __cdecl 成员函数一起使用 bind,在包含 <boost/bind.hpp> 之前 #define 宏 BOOST_MEM_FN_ENABLE_CDECL。
最好在项目选项中定义这些宏,在命令行上使用 –D,或作为使用了 bind 的翻译单元(.cpp 文件)的第一行。不遵守这个规则,当一个包含了 bind.hpp 的头文件出现在这些宏被定义之前,可能会导致隐蔽的错误。
【注意:这是一个不可移植扩展。它不是接口的一部分。】
【注意:有些编译器只对 __stdcall 关键字提供最小的支持。】
visit_each support(visit_each 支持)
bind 返回的函数对象支持到目前为止尚处于实验性和未文档化的 visit_each 枚举接口。
示例参见 bind_visitor.cpp。
Acknowledgements(感谢)
影响这个库设计的早期成就:
- Jaakko Järvi 的 Binder 库;
- Jaakko Järvi 和 Gary Powell(Binder 库的接任者)的 Lambda 库(现在成为 Boost 的一部分);
- Petter Urkedal 的 Extensions to the STL。
Doug Gregor 建议了一种访问者机制可以允许 bind 和 signal/slot 库进行互操作。
John Maddock 修复了一个 MSVC 特有的在 bind 和 type traits 库之间的冲突。
正式 review 期间,Ross Smith,Richard Crossley,Jens Maurer,Ed Brey 和其他人提出大量改进建议。review 主管者是 Darin Adler。
在和 Jaakko Järvi 的讨论中 bind 的精确语义更加优雅。
John Maddock 修复了一个 MSVC 特有的在 bind 和 iterator adaptors 库之间的冲突。
Dave Abrahams 改良了 bind 和 mem_fn 以支持在不完善编译器上的空返回。
Mac Murrett 通过 BOOST_BIND_ENABLE_PASCAL 实现并贡献了 "pascal" 支持。
可选的 bind(type<R>(), f, ...) 语法的灵感来自于和 Dave Abrahams 与 Joel de Guzman 的一次讨论。
Copyright © 2001, 2002 by Peter Dimov and Multi Media Ltd. Copyright 2003-2008 Peter Dimov. Distributed under the Boost Software License, Version 1.0. See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.