現在的位置: 首頁 > 黃專家專欄 > 正文

Boost – Function 分析

2014年10月30日 黃專家專欄 ⁄ 共 7168字 ⁄ 字型大小 評論關閉

本文假設了解 boost::function 相關用法

首先需要包含的頭文件為 boost/function.hpp

裡面內容比較簡單

1
2
3
4
5
6
7
8
9
10
11
#  if BOOST_FUNCTION_MAX_ARGS >= 0
#    include <boost/function/function0.hpp>
#  endif
#  if BOOST_FUNCTION_MAX_ARGS >= 1
#    include <boost/function/function1.hpp>
# endif
#  if BOOST_FUNCTION_MAX_ARGS >= 2
#    include <boost/function/function2.hpp>
#  endif
#  if BOOST_FUNCTION_MAX_ARGS >= 3
#    include <boost/function/function3.hpp>
#  endif
... ...

默認的 BOOST_FUNCTION_MAX_ARGS 為 10,說明最大支持為10個參數

那麼,可以知道引入了function0 ~ function10 共11個文件

第N個文件都是定義了支持 N 個參數的 function 類

我們以參數 BOOST_FUNCTION_MAX_ARGS = 4 來看看定義

boost/function/function4.hpp 頭文件里只有這樣幾行

1
2
3
#define BOOST_FUNCTION_NUM_ARGS 4
#include <boost/function/detail/maybe_include.hpp>
#undef BOOST_FUNCTION_NUM_ARGS

boost/function/detail/maybe_include.hpp 裡面其實就定義了 BOOST_FUNCTION_N

1
2
3
4
5
6
7
8
9
10
11
12
#if BOOST_FUNCTION_NUM_ARGS == 0
#  ifndef BOOST_FUNCTION_0
#    define BOOST_FUNCTION_0
#    include <boost/function/function_template.hpp>
#  endif
#elif BOOST_FUNCTION_NUM_ARGS == 1
#  ifndef BOOST_FUNCTION_1
#    define BOOST_FUNCTION_1
#    include <boost/function/function_template.hpp>
#  endif
#elif BOOST_FUNCTION_NUM_ARGS == 2
#  ifndef BOOST_FUNCTION_2
#    define BOOST_FUNCTION_2
#    include <boost/function/function_template.hpp>
#  endif
... ...

boost/function/function_template.hpp 首先看兩個宏定義

1
2
#define BOOST_FUNCTION_TEMPLATE_PARMS BOOST_PP_ENUM_PARAMS(BOOST_FUNCTION_NUM_ARGS, typename T)
#define BOOST_FUNCTION_TEMPLATE_ARGS BOOST_PP_ENUM_PARAMS(BOOST_FUNCTION_NUM_ARGS, T)

BOOST_FUNCTION_NUM_ARGS 就是當前文件支持的參數個數,當前是4 BOOST_FUNCTION_TEMPLATE_PARMS 是宏自身擴展,展開時可能如下:

1
2
3
4
#define BOOST_FUNCTION_TEMPLATE_PARMS BOOST_PP_ENUM_PARAMS(BOOST_FUNCTION_NUM_ARGS, typename T)
  // typename T0 , typename T1 , typename T2 , typename T3
  // 同樣 BOOST_FUNCTION_TEMPLATE_ARGS 展開如下
  // T0 , T1 , T2 , T3

可以看到,我們用宏展開後的結果,function里都是一些構造函數和賦值函數,所以應該主要工作都在基類中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
template<typename R , typename T0 , typename T1 , typename T2 , typename T3>
class function<R ( T0 , T1 , T2 , T3)> : public function4<R , T0 , T1 , T2 , T3> {
  typedef function4<R , T0 , T1 , T2 , T3> base_type;
  typedef function self_type;
  struct clear_type {};
  public:
  function() : base_type() {}

  // 模板的 sfinae 原則,避免整數被選入
  template<typename Functor>
    function(Functor f,
        typename enable_if_c<
        (boost::type_traits::ice_not<
         (is_integral<Functor>::value)>::value),
        int>::type = 0) : base_type(f) {}
  template<typename Functor,typename Allocator>

    // 同上
    function(Functor f, Allocator a,
        typename enable_if_c<(
          boost::type_traits::ice_not<(
            is_integral<Functor>::value)>::value),int>::type = 0) :
      base_type(f,a) {}
  function(clear_type*) : base_type() {}
  function(const self_type& f) : base_type(static_cast<const base_type&>(f)) {}
  function(const base_type& f) : base_type(static_cast<const base_type&>(f)) {}
  self_type& operator=(const self_type& f) {
    self_type(f).swap(*this);
    return *this;
  }
  template<typename Functor>
    typename enable_if_c<(boost::type_traits::ice_not<
        (is_integral<Functor>::value)>::value),
             self_type&>::type
               operator=(Functor f) {
                 self_type(f).swap(*this);
                 return *this;
               }
  self_type& operator=(clear_type*) {
    this->clear();
    return *this;
  }
  self_type& operator=(const base_type& f) {
    self_type(f).swap(*this);
    return *this;
  }
}

所看看它基類的內容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
template<typename R , typename T0 , typename T1 , typename T2 , typename T3>
class function4 : public function_base
{
  public:
    typedef R result_type;
    typedef boost::detail::function::basic_vtable4<R , T0 , T1 , T2 , T3> vtable_type;

    struct clear_type {};
    template<typename Functor>
      function4(Functor f,
          typename enable_if_c<(boost::type_traits::ice_not<
            (is_integral<Functor>::value)>::value), int>::type = 0) {
        this->assign_to(f);
      }

    // 主要賦值在這個函數
    template<typename Functor>
      void assign_to(Functor f) {
        using detail::function::vtable_base;

        // 以下兩行是得到 Functor 的類型
        // 這個是由 tag 做萃取器的
        typedef typename detail::function::get_function_tag<Functor>::type tag;
        typedef detail::function::get_invoker4<tag> get_invoker;
        typedef typename handler_type::invoker_type invoker_type;
        typedef typename get_invoker::template apply<Functor, R ,T0 , T1 , T2 , T3> handler_type;

        // vtable_type 負責實際 Functor 映射到內部 function_buffer 的管理
        // 這裡之所以用靜態的是因為同一種類型的 assign_to都是一樣的策略
        // 不同 Functor 自然生成不同的 assign_to,那麼 stored_vtable 也自然不同了
        static vtable_type stored_vtable =
        { { &manager_type::manage }, &invoker_type::invoke };
        if (stored_vtable.assign_to(f, functor)) {
          std::size_t value = reinterpret_cast<std::size_t>(&stored_vtable.base);
          if (boost::has_trivial_copy_constructor<Functor>::value &&
              boost::has_trivial_destructor<Functor>::value &&
              detail::function::function_allows_small_object_optimization<Functor>::value) {
            value |= (std::size_t)0x01;
            vtable = reinterpret_cast<detail::function::vtable_base *>(value);
          } else {
            vtable = 0;
          }
        }
      }
    ... ...
}

上面看有兩個成員變數是比較重要的,一個是 vtable, 一個是 function

他們都在基類 function_base 中被描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class function_base {
  ... ...
    detail::function::vtable_base* vtable;
  // 真正存儲的指針
  mutable detail::function::function_buffer functor;
};

union function_buffer {
  mutable void* obj_ptr;  // 對象指針類型
  mutable void (*func_ptr)(); // 函數指針類型

  // 指針本身的類型, 比如是const約束? volite約束?
  struct type_t {
    const detail::sp_typeinfo* type;
    bool const_qualified;
    bool volatile_qualified;
  } type;

  // 成員函數指針的結構
  struct bound_memfunc_ptr_t {
    void (X::*memfunc_ptr)(int);
    void* obj_ptr;
  } bound_memfunc_ptr;

  // 對象引用類型
  struct obj_ref_t {
    mutable void* obj_ptr;
    bool is_const_qualified;
    bool is_volatile_qualified;
  } obj_ref;

  // 小函數對象的優化
  // 如果是小函數對象,那麼直接構造在這個 union 上
  mutable char data;
};

// 這個是幹嘛用的現在還不清楚
struct vtable_base {
  void (*manager)(const function_buffer& in_buffer,
      function_buffer& out_buffer,
      functor_manager_operation_type op);
};

萃取器的 tag 代碼如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
struct function_ptr_tag {};
struct function_obj_tag {};
struct member_ptr_tag {};
struct function_obj_ref_tag {};

template<typename F>
class get_function_tag {
  // 這是個依次迭代的關係
  // 巧妙啊,這樣解決了定義 type 為不同類型的問題
  // 其實是一個 if-else 的編譯期選擇綁定
  typedef typename mpl::if_c<(is_pointer<F>::value),
          function_ptr_tag,
          function_obj_tag>::type ptr_or_obj_tag;
  typedef typename mpl::if_c<(is_member_pointer<F>::value),
          member_ptr_tag,
          ptr_or_obj_tag>::type ptr_or_obj_or_mem_tag;
  typedef typename mpl::if_c<(is_reference_wrapper<F>::value),
          function_obj_ref_tag,
          ptr_or_obj_or_mem_tag>::type or_ref_tag;
  public:
  typedef or_ref_tag type;
};

// vtable_type 大概代碼如下
typedef boost::detail::function::basic_vtable0<R> vtable_type;
template<typename R >
struct basic_vtable4
{
  template<typename F>
    bool assign_to(F f, function_buffer& functor) {
      typedef typename get_function_tag<F>::type tag;
      return assign_to(f, functor, tag());
    }

  // 以下重載了幾種 tag
  // 普通指針對象
  template<typename FunctionPtr>
    bool assign_to(FunctionPtr f, function_buffer& functor, function_ptr_tag) {
      this->clear(functor);
      if (f) {
        // 普通函數指針都是轉換成 (void (*)())(f) 指針
        functor.func_ptr = (void (*)())(f);
        return true;
      } else {
        return false;
      }
    }

  // 仿函數對象
  template<typename FunctionObj>
    bool assign_to(FunctionObj f, function_buffer& functor, function_obj_tag) {
      if (!boost::detail::function::has_empty_target(boost::addressof(f))) {
        // 小對象優化
        assign_functor(f, functor,
            mpl::bool_<(function_allows_small_object_optimization<FunctionObj>::value)>());
        return true;
      } else {
        return false;
      }
    }

  // 具體的小對象優化
  template<typename FunctionObj>
    void assign_functor(FunctionObj f, function_buffer& functor, mpl::false_) {
      functor.obj_ptr = new FunctionObj(f);
    }

  template<typename FunctionObj>
    void assign_functor(FunctionObj f, function_buffer& functor, mpl::true_) {
      new ((void*)&functor.data) FunctionObj(f);
    }
};

最後調用一目了然了

1
2
3
4
5
6
inline function4<R , T0 , T1 , T2 , T3>::operator()( T0 a0 , T1 a1 , T2 a2 , T3 a3) const {
  if (this->empty())
    boost::throw_exception(bad_function_call());
  return get_vtable()->invoker
    (this->functor , a0 , a1 , a2 , a3);
}

抱歉!評論已關閉.