Boost文档翻译:第1章. Boost.Bind,Chapter 1. Boost.Bind
boost :: bind ,是对标准库函数 std :: bind1st 和 std :: bind2nd 的泛化。 它支持任意的函数对象、函数、函 数指针和成员函数指针 。 它能够 将任意参数绑定为特定的值。它还能够将输入参数路由(route)到任意位置。 bind ,对于目标函数对象没有任何要求;尤其 是,它并不需要提供 result_type 、 first_argument_type 和 second_argument_type 这些标准类型定义(typedef)。
看以下定义:
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 ) ,会产生一个“零元”("nullary")函数对象, 该对象不需要任何参数,而返回 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(i), _1);
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) ,也就是0
某些编译器无法识别 bind < R >( f , ...) 语法 。出于 可移植性方面的考虑,我们还支持另外 一种写法:
boost::bind(boost::type< int >(), f, _1, _1)(x);
注意 ,这里所说的另外一种写法,仅仅是在不得以情况下的写法。它并不是所设计的接口的组成部分。
如果 该个函数对象暴露出了一个名为 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 );
指向成员函数的指针,和指向数据成员的指针,都不是函数对象,因为它们不支持 operator () 。出于便利 性的考虑, bind 还接受传入成员的指针作为它的第一个参数, 而其行为,类似于,使用 boost::mem_fn 来将该个成员指针转换成 一个函数对象。 换句话说, 以下表达式
bind(&X::f, args)
等价 于
bind < R >( mem_fn (& X :: f ), args )
其中 的 R ,指的是, X :: f 的返回数据类型 (对于成员函数来说是这样的) ,或者是该个成员本身的数据类型 (对于数据成员来说是这样的) 。
[注意 : 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); // (x 的内部副本 ).f(i)
bind(&X::f, p, _1)(i); // (p 的内部副本 )->f(i)
后面两个示例 的有趣之处在于,它们产生 了两个“自包含的”函数对象。 bind (& X :: f , x , _1 ) 中储存了 x 的一个副本。 bind (& X :: f , p , _1 ) 中储存了 p 的一个副本, 同时,由于 p 是一个 boost::shared_ptr ,所以, 这个函数对象中会保留当前 X 实例 的一个引用,并且 ,即使 p 离开了其作用域或被重置( reset () ),也仍然有效。
向 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 来实现, 它会将它的第一个参数 当 成 一个 函数对象, 并对参数列表中剩下的参数应用这个函数对象。 为了提供便利,在头文件 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只是简单 地将参数列表原样传递给另一个函数对象。
protect.hpp 头文件中包含着 protect 的实现。 要想保护 ( protect ) 某个bind 函数对象,使得它不被算值,则这样写: protect ( bind ( f , ...)) 。
为了使用方便,由 bind 产生的那些函数对象都会重载逻辑非操作符operator ! ,还有那些关系及逻辑操作符 == 、 != 、 < 、 <= 、 > 、 >= 、 && 、 || 。
! bind ( f , ...) 等价 于 bind ( logical_not (), bind ( f , ...)) ,其中 , logical_not 是一个函数对象, 它接受一个参数 x ,并返回 ! x 。
bind ( f , ...) op x ,其中, op 是一个关系或逻辑操作符,整个表达式等价于 bind ( relation (), bind ( f , ...), x ) ,其中 , relation ,是一个函数对象,它接受两个参数 a 和 b ,并且返回 a op b 。
这些东西的意义在于,妳可以方便地将 bind 的结果反转。
std::remove_if(first, last, !bind(&X::visible, _1)); // 删除 不可见的对象
还可以将 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)); // 按照名字 来排序
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 )));
}
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 );
}
一个通用的规则是,由 bind 生成的函数对象, 是以引用的方式来接受参数的,因而,无法接受 非常量的临时变量或字面常量。 这是 由C++语言的当前(2003)版本造成的固有限制,被称为 转发问题 。 ( 在下一个版本的标准中会得到修复,也就是通常称之为 C++0x 的版本。 )
这个库中,所使用的特征形式是
template < class T> void f(T & t);
它使用这种形式来接受任意的数据类型,并且未加修改地将它们向后传递。正如前面所说,这种形式,不支持非常量的右值。
对于那些支持对函数模板进行部分排序的编译器,可通过添加一个重载来解决这个问题:
template < class T> void f(T & t);
template < class T> void f(T const & t);
遗憾 的是,使用这种方式,在有9个参数的情况下,就需要实现 512 个重载,这样狠不实际。在这个库中,选择了覆盖其中一个小子集:对于一个和二个参数的情况,它提供了全部可能情况的常量重载,对于大于等于三个参数的情况,它提供了单个重载情况,即是全部参数都是常量引用的情况。这种处理方式,覆盖了大部分合理情况。
参考专门 的 问题排查小节 。
可能 是因为妳使用了通用的 bind < R >( f , ...) 语法, 这将导致 bind 不再“检查”f 以探测参数个数和返回数据类型方面的错误。
第一 种形式 , 会要求 bind 对 f 的类型进行检查,确认 它的元数(arity(参数个数))及返回数据类型。 元数相关的错误会在“绑定时刻”("bind time")检测。显然 ,这种语法会对 f 有所要求。 它必须是一个函数,或是一个函数指针,或者一个成员函数指针,或是一个定义了名为 result_type 的嵌套类型的函数对象;简单 地说,它必须能够被 bind 所识别。
第二 种形式,会要求 bind 不要对 f 的类型进行识别。 它通常用于那些没有暴露或无法暴露出 result_type 的函数对象, 但也可用于非标准的函数。例如,目前 的实现中,无法自动识别 可变数量参数的函数,比如 printf ,所以妳就需要使用 bind < int >( printf , ...) 了。注意 ,另外还提供了一个 bind ( type < R >(), f , ...) 语法,用于解决可移植性方面的问题。
另一个重要因素就是,那些 不具有部分模板特化功能或函数模板部分排序功能的编译器, 在遇到 f 是函数对象的情况时,无法处理第一种语法 ,并且,遇到 f 是函数(指针)或成员函数指针时大部分都无法处理第二种语法。
某些情况 下可以。 在某些平台上,指向外部"C" (extern "C") 函数的指针,其本质与普通函数指针是相同的,所以能够与 bind 配套使用。 别的平台上,会将它们当成另外的类型对待。 在专门为对应平台而实现的 bind 中,应当透明地处理好这个问题; 而目前我们所谈论的这个实现中,并未处理这个问题。按照前文 所说的,解决方法就是, 将该个函数当作 通用函数对象 来对待,并且使用 bind < R >( f , ...) 语法。
一般来说,不可移植的扩展,应当被关闭, 以避免被厂商套牢。 在某些 适当 的宏 被自动定义的情况下, 妳可能会偶然地使用了这些方面的功能,却没有意识到,妳的代码可能已经不具有可移植性了。另外 , 在某些编译器中, 有些选项, 可以将 __stdcall ( __fastcall )设置成它们的默认调用风格, 这种情况下, 也不需要特别对它们提供支持。
在 bind ( f , a1 , a2 , ..., aN ) 这样一个表达式中,函数对象 f ,必须能够刚好接受N 个参数。 这方面的错误,一般是在“绑定时刻”检测的; 换句话说,相关 的编译错误, 是在 bind () 被调用的地方报告的:
int f( int , int );
int main()
{
boost :: bind ( f , 1 ); // 错误 , f需要两个参数
boost :: bind ( f , 1 , 2 ); // OK
}
这个错误的另一种表现形式就是,忘记了一点,成员函数都有一个隐藏的"this"参数:
struct X
{
int f ( int );
}
int main()
{
boost :: bind (& X :: f , 1 ); // 错误 , X::f需要两个参数
boost :: bind (& X :: f , _1 , 1 ); // 正确
}
与普通的函数调用相同,被绑定的函数对象,必须 与传入的参数列表相兼容。如果 发生了不兼容的情况,那么,这种错误通常是在编译器在“调用时刻”检测到的, 所产生的结果是, 在 bind . hpp 中类似下面 这样的某行代码中 报告出错误:
return f(a[a1_], a[a2_]);
以下示例展示了这种错误:
int f( int );
int main()
{
boost :: bind ( f , "incompatible" ); // 目前 为止没有问题,因为未发生调用
boost :: bind ( f , "incompatible" )(); // 错误 , "incompatible" 并不是 int
boost :: bind ( f , _1 ); // 没有问题
boost :: bind ( f , _1 )( "incompatible" ); // 错误 , "incompatible" 并不是 int
}
占位符 _N ,命中 的是在“调用时刻”传入的参数列表中位于第 N 个位置的参数。自然 地,当妳试图访问到超出这个列表范围的参数时,就会出错:
int f( int );
int main()
{
boost :: bind ( f , _1 ); // 目前 没问题
boost :: bind ( f , _1 )(); // 错误 ,第1个位置没有参数
}
这个错误,通常在 bind . hpp 中类似下面的某行代码中报告:
return f(a[a1_]);
在模拟 std :: bind1st ( f , a ) 的时候, 与此相关的一个常见错误就是, 写出了 bind ( f , a , _2 ) ,而正确的写法应当是 bind ( f , a , _1 ) 。
bind ( f , a1 , a2 , ..., aN ) 这种语法 会导致自动对 f 的类型进行识别。 它并不是对于任意类型的函数对象都能用的; f 必须 是一个函数或成员函数指针。
可以针对那些定义 了 result_type 的函数对象使用这种语法,但是只有 在支持部分特化和部分排序的编译器中才能使用。
bind < R >( f , a1 , a2 , ..., aN ) 这种语法 支持任意 的函数对象。
可以(但不建议)使用这种语法来绑定函数或成员函数指针,但只在支持部分排序的编译器中才可使用。
默认情况 下, bind ( f , a1 , a2 , ..., aN ) 这种语法 能识别“普通”的 C++函数 和函数指针。 那些 以不同的风格进行调用的函数 ,或者 是那些接受可变个数参数的函数,比如, std :: printf ,就不支持。 更通用的 bind < R >( f , a1 , a2 ,..., aN ) 语法 则支持非标准函数。
在某些平台上,外部"C"(extern "C")函数,例如, std :: strcmp ,也不被 bind 的较短形式语法所支持。
试图对一个重载函数进行绑定的话,通常会产生错误,因为,无法指定要对重载函数中的哪一个进行绑定。对于拥有常量和非常量两种重载的成员函数来说,这是常见的错误,以下简单示例中展示这一点:
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 );
}
由 bind 所产生的那些函数对象, 并不遵循标准模板库中的 一元函数 或 二元函数 概念 ,即 便 那些函数对象本身确实 是一元或二元操作也是如此。这是因为, 这些函数对象类型中缺少公有的 result_type 和 argument_type 或 first_argument_type 和 second_argument_type 类型定义。如果确实需要 这些类型定义的话,那么 ,可使用辅助函数 make_adaptable , 它会将一元和二元函数对象适配到符合这些概念。 这样,由 bind 产生的一元和二元函数对象就能够与标准模板库中的模板配套使用了,例如 std::unary_negate 和 std::binary_negate 。
make_adaptable 函数 是在 <boost/bind/make_adaptable.hpp> 中定义的, 它必须在 <boost/bind.hpp> 之外显式包含:
#include <boost/bind/make_adaptable.hpp>
template < class R , class F > unspecified-type make_adaptable ( F f );
template < class R , class A1 , class F > unspecified-unary-functional-type make_adaptable ( F f );
template < class R , class A1 , class A2 , class F > unspecified-binary-functional-type make_adaptable ( F f );
template < class R , class A1 , class A2 , class A3 , class F > unspecified-ternary-functional-type make_adaptable ( F f );
template < class R , class A1 , class A2 , class A3 , class A4 , class F > unspecified-4-ary-functional-type make_adaptable ( F f );
以下示例,展示了,如何利用 make_adaptable 来制造一个判定式,用于判定 “不是空白” :
typedef char char_t;
std::locale loc( "" );
const std::ctype<char_t>& ct = std::use_facet<std::ctype<char_t> >(loc);
auto isntspace = std::not1(boost::make_adaptable< bool , char_t>(boost::bind(&std::ctype<char_t>::is, &ct, std::ctype_base::space, _1)));
在这个示例中, bind 创建 了“是空白” ( 一元 )判定 式。然后 ,这个判定式被传递给 make_adaptable ,使得 所创建出的 函数对象遵循一元函数( Unary Function )概念,进而作为 std::not1 的参数使用。
某些编译器, 在处理函数特征签名中的顶级 const 关键字时会有问题:
int f( int const );
int main()
{
boost :: bind ( f , 1 ); // 错误
}
解决方法 :删除参数所带的 const 限制符。
namespace boost
{
// 不带参数
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 ) ());
// 带一个参数
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 );
// 带两个参数
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 );
// 在实现中,还为更多参数的情况定义了额外的重载
}
namespace
{
unspecified-placeholder-type-1 _1 ;
unspecified-placeholder-type-2 _2 ;
unspecified-placeholder-type-3 _3 ;
// 在实现中,还定义了其它的占位符
}
由 bind 返回的所有的 unspecified-N 类型,都是可复制构造的( CopyConstructible )。 unspecified-N :: result_type ,被定义为 unspecified-N :: operator () 的返回数据类型。
所有 的 unspecified-placeholder-N 数据类型都是可复制构造的( CopyConstructible )。它们 的复制构造函数不会抛出异常。
函数μ ( x , v1 , v2 , ..., vm ) ,其中, m 是一个非负整数, 其定义是:
•. x . get () ,其中,对于某个类型 T 来说, x 的类型是 boost::reference_wrapper < T > ;
•. vk ,其中,对于某个正整数 k , x 是占位符 _k ( 的一个副本 );
•. x ( v1 , v2 , ..., vm ) , x 是由 bind 返回的某个函数对象( 的一个副本 ),则结果是这个;
•. x ,其它情况则结果是这个。
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 ) 。
具体 的实现中,允许提供更多的 bind 重载, 以支持更多的参数个数,或者其它形式的函数指针。
•. 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 (访问 器示例 )
•. libs/bind/test/bind_stdcall_test.cpp (测试 __stdcall 函数)
•. libs/bind/test/bind_stdcall_mf_test.cpp (测试 __stdcall 成员函数)
•. libs/bind/test/bind_fastcall_test. (测试 __fastcall 函数)
•. libs/bind/test/bind_fastcall_mf_test.cpp (测试 __fastcall 成员函数)
•. Boost.Config
在这个实现中,支持多达9个参数的函数对象。这个限制是由具体实现决定的,不是由最初设计而决定的。
某些平台上,允许存在着多种(成员)函数类型,它们因为其调用风格(这些函数在调用时遵循的规则:参数如何传递;返回值如何处理;以及,(如果有的话)谁来清理栈)的不同而被区别为不同的类型。
要将 bind 与 __stdcall 函数配套使用,则在包含 < boost / bind . hpp > 之前定义( #define )这个宏 BOOST_BIND_ENABLE_STDCALL 。
要将 bind 与 __stdcall 成员函数配套使用,则在包含 < boost / bind . hpp > 之前定义( #define )这个宏 BOOST_MEM_FN_ENABLE_STDCALL 。
要将 bind 与 __fastcall 函数配套使用,则在包含 < boost / bind . hpp > 之前定义( #define )这个宏 BOOST_BIND_ENABLE_FASTCALL 。
要将 bind 与 __fastcall 成员函数配套使用,则在包含 < boost / bind . hpp > 之前定义( #define )这个宏 BOOST_MEM_FN_ENABLE_FASTCALL 。
要将 bind 与 pascal 函数配套使用,则在包含 < boost / bind . hpp > 之前定义( #define )这个宏 BOOST_BIND_ENABLE_PASCAL 。
要将 bind 与 __cdecl 成员函数配套使用,则在包含 < boost / bind . hpp > 之前定义( #define )这个宏 BOOST_MEM_FN_ENABLE_CDECL 。
最好 是用以下方式来定义这些宏: 在项目的配置选项中定义;在命令行中通过 - D 选 项 来定义;或者 在用到了 bind 的翻译单元( .cpp 文件)的第一行定义。 不遵守这个规则的话,可能会引起奇特的错误,因为,某个 头文件可能在尚未定义这些宏的情况下就包含了 bind . hpp 。
[注意 : 这是一个不可移植的扩展。它不是接口的一部分。 ]
[注意 : 某些编译器 仅对 __stdcall 关键字提供了最小化的支持。 ]
由 bind 所返回的函数对象,支持目前 尚处于试验状态、未被文档说明的 visit_each 枚举接口。
参考 bind_visitor.cpp 以了解相关示例。
维权志愿 者 刘沙沙
张 柏芝
超杀女
杨幂
Your opinionsHxLauncher: Launch Android applications by voice commands