• 3.2. Boost.Bind

    3.2. Boost.Bind

    Boost.Bind 是这样的一个库,它简化了由C++标准中的 std::bind1st()std::bind2nd() 模板函数所提供的一个机制:将这些函数与几乎不限数量的参数一起使用,就可以得到指定签名的函数。 这种情形的一个最好的例子就是在C++标准中定义的多个不同算法。

    1. #include <iostream>
    2. #include <vector>
    3. #include <algorithm>
    4.  
    5. void print(int i)
    6. {
    7. std::cout << i << std::endl;
    8. }
    9.  
    10. int main()
    11. {
    12. std::vector<int> v;
    13. v.push_back(1);
    14. v.push_back(3);
    15. v.push_back(2);
    16.  
    17. std::for_each(v.begin(), v.end(), print);
    18. }
    • 下载源代码

    算法 std::for_each() 要求它的第三个参数是一个仅接受正好一个参数的函数或函数对象。 如果 std::for_each() 被执行,指定容器中的所有元素 - 在上例中,这些元素的类型为 int - 将按顺序被传入至 print() 函数。 但是,如果要使用一个具有不同签名的函数的话,事情就复杂了。 例如,如果要传入的是以下函数 add(),它要将一个常数值加至容器中的每个元素上,并显示结果。

    1. void add(int i, int j)
    2. {
    3. std::cout << i + j << std::endl;
    4. }

    由于 std::for_each() 要求的是仅接受一个参数的函数,所以不能直接传入 add() 函数。 源代码必须要修改。

    1. #include <iostream>
    2. #include <vector>
    3. #include <algorithm>
    4. #include <functional>
    5.  
    6. class add
    7. : public std::binary_function<int, int, void>
    8. {
    9. public:
    10. void operator()(int i, int j) const
    11. {
    12. std::cout << i + j << std::endl;
    13. }
    14. };
    15.  
    16. int main()
    17. {
    18. std::vector<int> v;
    19. v.push_back(1);
    20. v.push_back(3);
    21. v.push_back(2);
    22.  
    23. std::for_each(v.begin(), v.end(), std::bind1st(add(), 10));
    24. }
    • 下载源代码

    以上程序将值10加至容器 v 的每个元素之上,并使用标准输出流显示结果。 源代码必须作出大幅的修改,以实现此功能:add() 函数已被转换为一个派生自 std::binary_function 的函数对象。

    Boost.Bind 简化了不同函数之间的绑定。 它只包含一个 boost::bind() 模板函数,定义于 boost/bind.hpp 中。 使用这个函数,可以如下实现以上例子:

    1. #include <boost/bind.hpp>
    2. #include <iostream>
    3. #include <vector>
    4. #include <algorithm>
    5.  
    6. void add(int i, int j)
    7. {
    8. std::cout << i + j << std::endl;
    9. }
    10.  
    11. int main()
    12. {
    13. std::vector<int> v;
    14. v.push_back(1);
    15. v.push_back(3);
    16. v.push_back(2);
    17.  
    18. std::for_each(v.begin(), v.end(), boost::bind(add, 10, _1));
    19. }
    • 下载源代码

    add() 这样的函数不再需要为了要用于 std::for_each() 而转换为函数对象。 使用 boost::bind(),这个函数可以忽略其第一个参数而使用。

    因为 add() 函数要求两个参数,两个参数都必须传递给 boost::bind()。 第一个参数是常数值10,而第二个参数则是一个怪异的 _1

    1_ 被称为占位符(placeholder),定义于 Boost.Bind。 除了 1,Boost.Bind 还定义了 __23_。 通过使用这些占位符,boost::bind() 可以变为一元、二元或三元的函数。 对于 1_, boost::bind() 变成了一个一元函数 - 即只要求一个参数的函数。 这是必需的,因为 std::for_each() 正是要求一个一元函数作为其第三个参数。

    当这个程序执行时,std::foreach() 对容器 _v 中的第一个元素调用该一元函数。 元素的值通过占位符 _1 传入到一元函数中。 这个占位符和常数值被进一步传递到 add() 函数。 通过使用这种机制,std::for_each() 只看到了由 boost::bind() 所定义的一元函数。 而 boost::bind() 本身则只是调用了另一个函数,并将常数值或占位符作为参数传入给它。

    下面这个例子通过 boost::bind() 定义了一个二元函数,用于 std::sort() 算法,该算法要求一个二元函数作为其第三个参数。

    1. #include <boost/bind.hpp>
    2. #include <vector>
    3. #include <algorithm>
    4.  
    5. bool compare(int i, int j)
    6. {
    7. return i > j;
    8. }
    9.  
    10. int main()
    11. {
    12. std::vector<int> v;
    13. v.push_back(1);
    14. v.push_back(3);
    15. v.push_back(2);
    16.  
    17. std::sort(v.begin(), v.end(), boost::bind(compare, _1, _2));
    18. }
    • 下载源代码

    因为使用了两个占位符 1_ 和 2,所以 boost::bind() 定义了一个二元函数。 std::sort() 算法以容器 _v 的两个元素来调用该函数,并根据返回值来对容器进行排序。 基于 compare() 函数的定义,容器将被按降序排列。

    但是,由于 compare() 本身就是一个二元函数,所以使用 boost::bind() 确是多余的。

    1. #include <boost/bind.hpp>
    2. #include <vector>
    3. #include <algorithm>
    4.  
    5. bool compare(int i, int j)
    6. {
    7. return i > j;
    8. }
    9.  
    10. int main()
    11. {
    12. std::vector<int> v;
    13. v.push_back(1);
    14. v.push_back(3);
    15. v.push_back(2);
    16.  
    17. std::sort(v.begin(), v.end(), compare);
    18. }
    • 下载源代码

    不过使用 boost::bind() 还是有意义的。例如,如果容器要按升序排列而又不能修改 compare() 函数的定义。

    1. #include <boost/bind.hpp>
    2. #include <vector>
    3. #include <algorithm>
    4.  
    5. bool compare(int i, int j)
    6. {
    7. return i > j;
    8. }
    9.  
    10. int main()
    11. {
    12. std::vector<int> v;
    13. v.push_back(1);
    14. v.push_back(3);
    15. v.push_back(2);
    16.  
    17. std::sort(v.begin(), v.end(), boost::bind(compare, _2, _1));
    18. }
    • 下载源代码

    该例子仅改变了占位符的顺序:2_ 被作为第一参数传递,而 1_ 则被作为第二参数传递至 compare(),这样即可改变排序的顺序。