3.4. Boost.Function

为了封装函数指针,Boost.Function 提供了一个名为 boost::function 的类。 它定义于 boost/function.hpp,用法如下:

  1. #include <boost/function.hpp>
  2. #include <iostream>
  3. #include <cstdlib>
  4. #include <cstring>
  5.  
  6. int main()
  7. {
  8. boost::function<int (const char*)> f = std::atoi;
  9. std::cout << f("1609") << std::endl;
  10. f = std::strlen;
  11. std::cout << f("1609") << std::endl;
  12. }

boost::function 可以定义一个指针,指向具有特定签名的函数。 以上例子定义了一个指针 f,它可以指向某个接受一个类型为 const char* 的参数且返回一个类型为 int 的值的函数。 定义完成后,匹配此签名的函数均可赋值给这个指针。 这个例程就是先将 std::atoi() 赋值给 f,然后再将它重赋值为 std::strlen()

注意,给定的数据类型并不需要精确匹配:虽然 std::strlen() 是以 std::sizet 作为返回类型的,但是它也可以被赋值给 _f

因为 f 是一个函数指针,所以被赋值的函数可以通过重载的 operator()() 操作符来调用。 取决于当前被赋值的是哪一个函数,在以上例子中将调用 std::atoi()std::strlen()

如果 f 未赋予一个函数而被调用,则会抛出一个 boost::bad_function_call 异常。

  1. #include <boost/function.hpp>
  2. #include <iostream>
  3.  
  4. int main()
  5. {
  6. try
  7. {
  8. boost::function<int (const char*)> f;
  9. f("");
  10. }
  11. catch (boost::bad_function_call &ex)
  12. {
  13. std::cout << ex.what() << std::endl;
  14. }
  15. }

注意,将值 0 赋给一个 boost::function 类型的函数指针,将会释放当前所赋的函数。 释放之后再调用它也会导致 boost::bad_function_call 异常被抛出。 要检查一个函数指针是否被赋值某个函数,可以使用 empty() 函数或 operator bool() 操作符。

通过使用 Boost.Function,类成员函数也可以被赋值给类型为 boost::function 的对象。

  1. #include <boost/function.hpp>
  2. #include <iostream>
  3.  
  4. struct world
  5. {
  6. void hello(std::ostream &os)
  7. {
  8. os << "Hello, world!" << std::endl;
  9. }
  10. };
  11.  
  12. int main()
  13. {
  14. boost::function<void (world*, std::ostream&)> f = &world::hello;
  15. world w;
  16. f(&w, boost::ref(std::cout));
  17. }

在调用这样的一个函数时,传入的第一个参数表示了该函数被调用的那个特定对象。 因此,在模板定义中的左括号后的第一个参数必须是该特定类的指针。 接下来的参数才是表示相应的成员函数的签名。

这个程序还使用了来自 Boost.Ref 库的 boost::ref(),它提供了一个方便的机制向 Boost.Function 传递引用。