Boost C++ 库

...世界上最受尊敬和专业设计的 C++ 库项目之一。 Herb SutterAndrei Alexandrescu, C++ Coding Standards

第1章 Boost.Bind

目录

目的
将 bind 与函数和函数指针一起使用
将 bind 与函数对象一起使用
将 bind 与成员指针一起使用
使用嵌套 bind 进行函数组合
重载运算符(Boost 1.33 中的新功能)
示例
将 bind 与标准算法一起使用
将 bind 与 Boost.Function 一起使用
局限性
常见问题解答
为什么这段代码无法编译?
为什么这段代码可以编译?它不应该编译。
bind(f, ...)bind<R>(f, ...) 之间有什么区别?
bind 可以与 Windows API 函数一起使用吗?
bind 可以与 COM 方法一起使用吗?
bind 可以与 Mac toolbox 函数一起使用吗?
bind 可以与 extern "C" 函数一起使用吗?
为什么 bind 不会自动识别非标准函数?
故障排除
参数数量不正确
无法使用指定的参数调用函数对象
访问不存在的参数
不恰当地使用 bind(f, ...)
不恰当地使用 bind<R>(f, ...)
绑定非标准函数
绑定重载函数
建模 STL 函数对象概念
const 在签名中
MSVC 特定:using boost::bind;
MSVC 特定:类模板遮蔽函数模板
MSVC 特定:... 在签名中被视为类型
接口
概要
通用要求
通用定义
bind
附加重载
实现
文件
依赖项
参数数量
__stdcall__cdecl__fastcallpascal 支持
visit_each 支持
致谢

boost::bind 是标准函数 std::bind1ststd::bind2nd 的泛化。它支持任意函数对象、函数、函数指针和成员函数指针,并且能够将任何参数绑定到特定值或将输入参数路由到任意位置。bind 对函数对象没有任何要求;特别是,它不需要 result_typefirst_argument_typesecond_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) 将生成一个“空元”函数对象,它不接受任何参数并返回 f(1, 2)。类似地,bind(g, 1, 2, 3)() 等价于 to 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::refboost::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), i.e. zero

某些编译器在 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::refboost::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)

其中 RX::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);			// (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 的副本,并且由于 pboost::shared_ptr,因此函数对象保留对其 X 实例的引用,即使 p 超出范围或 reset(),它仍将保持有效。

传递给 bind 的某些参数可能是嵌套的bind 表达式本身

bind(f, bind(g, _1))(x);               // f(g(x))

当调用函数对象时,内部bind 表达式会以未指定的顺序进行求值;求值结果随后在外部 bind 求值时替换到它们的位置。在上面的示例中,当使用参数列表 (x) 调用函数对象时,首先对 bind(g, _1)(x) 进行求值,得到 g(x),然后对 bind(f, g(x))(x) 进行求值,得到最终结果 f(g(x))

bind 的此功能可用于执行函数组合。有关演示如何使用 bind 实现与 Boost.Compose 类似的功能的示例,请参见 bind_as_compose.cpp

请注意,第一个参数(绑定的函数对象)不会被求值,即使它是 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 生成的函数对象重载了逻辑非运算符 ! 以及关系运算符和逻辑运算符 ==, !=, <, <=, >, >=, &&, ||

!bind(f, ...) 等价于 bind(logical_not(), bind(f, ...)),其中 logical_not 是一个函数对象,它接受一个参数 x 并返回 !x

bind(f, ...) op x,其中 op 是关系运算符或逻辑运算符,等价于 bind(relation(), bind(f, ...), x),其中 relation 是一个函数对象,它接受两个参数 ab 并返回 a op b

这在实践中意味着您可以方便地否定 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
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 生成的函数对象通过引用获取其参数,因此不能接受非常量临时对象或文字常量。这是当前 (2003) C++ 语言固有的局限性,称为 转发问题。(它将在通常称为 C++0x 的下一个标准中得到修复。)

该库使用以下形式的签名

template<class T> void f(T & t);

接受任意类型的参数并将它们未经修改地传递下去。如前所述,这不适用于非常量右值。

在支持函数模板的部分排序的编译器上,可能的解决方案是添加重载

template<class T> void f(T & t);
template<class T> void f(T const & t);

不幸的是,这需要为九个参数提供 512 个重载,这是不切实际的。该库选择了一个小的子集:对于最多两个参数,它完全提供了 const 重载,对于三个或更多个参数的元数,它提供了一个额外的重载,其中所有参数都通过 const 引用获取。这涵盖了用例的合理部分。

可能是因为您使用了通用的 bind<R>(f, ...) 语法,从而指示 bind 不要“检查”f 以检测元数和返回类型错误。

第一种形式指示 bind 检查 f 的类型,以确定其元数(参数数量)和返回类型。元数错误将在“绑定时”检测到。当然,此语法对 f 提出了一些要求。它必须是函数、函数指针、成员函数指针或定义名为 result_type 的嵌套类型的函数对象;简而言之,它必须是 bind 可以识别的东西。

第二种形式指示 bind 不要尝试识别 f 的类型。它通常与不公开或无法公开 result_type 的函数对象一起使用,但也可以与非标准函数一起使用。例如,当前实现不会自动识别可变参数函数(如 printf),因此您必须使用 bind<int>(printf, ...)。请注意,出于可移植性原因,支持另一种 bind(type<R>(), f, ...) 语法。

需要考虑的另一个重要因素是,在 f 是函数对象时,没有部分模板特化或函数模板部分排序支持的编译器无法处理第一种形式,并且在大多数情况下,当 f 是函数(指针)或成员函数指针时,将无法处理第二种形式。

可以,如果您 #define BOOST_BIND_ENABLE_STDCALL。另一种方法是将该函数视为通用函数对象并使用 bind<R>(f, ...) 语法。

可以,如果您 #define BOOST_BIND_ENABLE_PASCAL。另一种方法是将该函数视为通用函数对象并使用 bind<R>(f, ...) 语法。

有时可以。在某些平台上,指向 extern "C" 函数的指针等同于“普通”函数指针,因此它们可以正常工作。其他平台将它们视为不同的类型。预计 bind 的平台特定实现会透明地处理此问题;此实现不会。与往常一样,解决方法是将该函数视为通用函数对象并使用 bind<R>(f, ...) 语法。

通常,非可移植扩展应默认关闭,以防止供应商锁定。如果适当的宏被自动定义,您可能会在没有意识到您的代码可能不再可移植的情况下意外地利用它们。此外,某些编译器可以选择使 __stdcall__fastcall)成为其默认调用约定,在这种情况下,无需单独支持。

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
}

与普通函数调用一样,绑定的函数对象必须与参数列表兼容。不兼容性通常会在“调用时”被编译器检测到,结果通常是在 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
}

占位符 _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)

bind(f, a1, a2, ..., aN) 形式会导致自动识别 f 的类型。它不适用于任意函数对象;f 必须是函数或成员函数指针。

可以将此形式与定义 result_type 的函数对象一起使用,但仅在支持部分特化和部分排序的编译器上。特别是,版本 7.0 之前的 MSVC 不支持函数对象的此语法。

bind<R>(f, a1, a2, ..., aN) 形式支持任意函数对象。

可以将此形式与函数或成员函数指针一起使用(但不建议这样做),但仅在支持部分排序的编译器上。特别是,版本 7.0 之前的 MSVC 不完全支持函数和成员函数指针的此语法。

默认情况下,bind(f, a1, a2, ..., aN) 形式识别“普通”C++ 函数和函数指针。使用不同调用约定的函数,或可变参数函数(如 std::printf)不起作用。通用的 bind<R>(f, a1, a2, ..., aN) 形式适用于非标准函数。

在某些平台上,extern "C" 函数(如 std::strcmp)无法被 bind 的简短形式识别。

另请参见 __stdcallpascal 支持

尝试绑定重载函数通常会导致错误,因为无法判断要绑定哪个重载。对于具有两个重载(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);
}

bind 生成的函数对象并不符合 STL 一元函数二元函数 的概念模型,即使这些函数对象是一元或二元操作,因为这些函数对象类型缺少公共的 typedef result_typeargument_typefirst_argument_type 以及 second_argument_type。 然而,在需要这些 typedef 的情况下,可以使用实用函数 make_adaptable 来使一元和二元函数对象适配这些概念。 这使得从 bind 产生的一元和二元函数对象可以与 STL 模板(例如 std::unary_negatestd::binary_negate)结合使用。

make_adaptable 函数在 <boost/bind/make_adaptable.hpp> 中定义,除了 <boost/bind/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,以便可以创建一个符合 一元函数 概念模型的函数对象,作为 std::not1 的参数。

一些编译器,包括 MSVC 6.0 和 Borland C++ 5.5.1,在函数签名中处理顶层 const 时存在问题。

int f(int const);

int main()
{
    boost::bind(f, 1);     // error
}

解决方法:从参数中移除 const 限定符。

在 MSVC(直到 7.0 版本)上,当使用 using 声明将 boost::bind 带入作用域时,

using boost::bind;

语法 bind<R>(f, ...) 不起作用。 解决方法:要么使用限定名 boost::bind,要么使用 using 指令代替。

using namespace boost;

在 MSVC(直到 7.0 版本)上,名为 bind 的嵌套类模板会遮蔽函数模板 boost::bind,从而破坏 bind<R>(f, ...) 语法。 不幸的是,一些库包含名为 bind 的嵌套类模板(讽刺的是,这种代码通常是 MSVC 特定的解决方法。)

解决方法是使用替代的 bind(type<R>(), f, ...) 语法。

MSVC(直到 7.0 版本)将可变参数函数(例如 std::printf)中的省略号视为类型。 因此,它会接受(在当前实现中不正确的)形式

bind(printf, "%s\n", _1);

并会拒绝正确的版本

bind<int>(printf, "%s\n", _1);
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
}

所有由 bind 返回的 unspecified-N 类型都是 CopyConstructible 的。unspecified-N::result_type 被定义为 unspecified-N::operator() 的返回类型。

所有 unspecified-placeholder-N 类型都是 CopyConstructible 的。 它们的复制构造函数不会抛出异常。

函数 μ(x, v1, v2, ..., vm),其中 m 是一个非负整数,定义为:

  • x 的类型为 boost::reference_wrapper<T> (对于某种类型 T)时,为 x.get()
  • x 是(_k 占位符的副本)对于某个正整数 k 时,为 vk
  • x 是(bind 返回的函数对象的副本)时,为 x(v1, v2, ..., vm)
  • 否则为 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
  • 抛出: 如果 FA1 的复制构造函数抛出异常,则抛出异常,否则不抛出任何异常。
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)
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)
  • 返回值: 一个函数对象 λ,使得表达式 λ(v1, v2, ..., vm) 等价于 f(μ(a1, v1, v2, ..., vm), μ(a2, v1, v2, ..., vm)),并隐式转换为 R
  • 抛出: 如果 FA1A2 的复制构造函数抛出异常,则抛出异常,否则不抛出任何异常。
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))
  • 抛出: 如果 A1A2 的复制构造函数抛出异常,则抛出异常,否则不抛出任何异常。
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)

允许实现提供额外的 bind 重载,以便支持更多参数或不同的函数指针变体。

此实现最多支持具有九个参数的函数对象。 这是一个实现细节,而不是设计的固有限制。

某些平台允许几种类型的(成员)函数,这些函数因其调用约定而异(调用函数的规则:如何传递参数,如何处理返回值,以及谁清理堆栈 - 如果有的话。)

例如,Windows API 函数和 COM 接口成员函数使用称为 __stdcall 的调用约定。 Borland VCL 组件使用 __fastcall。 Mac toolbox 函数使用 pascal 调用约定。

要将 bind__stdcall 函数一起使用,请在包含 <boost/bind/bind.hpp> 之前 #defineBOOST_BIND_ENABLE_STDCALL

要将 bind__stdcall 成员函数一起使用,请在包含 <boost/bind/bind.hpp> 之前 #defineBOOST_MEM_FN_ENABLE_STDCALL

要将 bind__fastcall 函数一起使用,请在包含 <boost/bind/bind.hpp> 之前 #defineBOOST_BIND_ENABLE_FASTCALL

要将 bind__fastcall 成员函数一起使用,请在包含 <boost/bind/bind.hpp> 之前 #defineBOOST_MEM_FN_ENABLE_FASTCALL

要将 bindpascal 函数一起使用,请在包含 <boost/bind/bind.hpp> 之前 #defineBOOST_BIND_ENABLE_PASCAL

要将 bind__cdecl 成员函数一起使用,请在包含 <boost/bind/bind.hpp> 之前 #defineBOOST_MEM_FN_ENABLE_CDECL

最好在项目选项中定义这些宏,通过命令行上的 -D,或作为使用 bind 的翻译单元(.cpp 文件)中的第一行。 如果不遵循此规则,当头文件在宏定义之前包含 bind.hpp 时,可能会导致难以察觉的错误。

[注意: 这是一个非可移植的扩展。 它不是接口的一部分。]

[注意: 某些编译器仅为 __stdcall 关键字提供最少的支持。]

bind 返回的函数对象支持实验性的且尚未公开文档的 visit_each 枚举接口。

有关示例,请参见 bind_visitor.cpp

影响库设计的早期工作:

Doug Gregor 建议,访问者机制将允许 bind 与信号/槽库互操作。

John Maddock 修复了 bindtype traits library 之间 MSVC 特定的冲突。

Ross Smith、Richard Crossley、Jens Maurer、Ed Brey 和其他人 Formal Review 期间提出了许多改进建议。 Review 管理员是 Darin Adler。

与 Jaakko Järvi 的讨论中,bind 的精确语义得到了改进。

Dave Abrahams 修复了 binditerator adaptors library 之间 MSVC 特定的冲突。

Dave Abrahams 修改了 bindmem_fn,以支持在功能不足的编译器上返回 void

Mac Murrett 贡献了由 BOOST_BIND_ENABLE_PASCAL 启用的 “pascal” 支持。

替代的 bind(type<R>(), f, ...) 语法受到与 Dave Abrahams 和 Joel de Guzman 的讨论的启发。

Agustín Bergé 将此文档移植到 Quickbook。