1. 程式人生 > 程式設計 >C++ STL 內 std::{bind/tuple/function} 簡單實現

C++ STL 內 std::{bind/tuple/function} 簡單實現

基本邏輯思考

首先是實現 function,這個比較簡單,過載 operator() 就好,這裡只實現對函式指標的包裝

其次是實現 tuple,這個會比較繞,通過模板取第一個引數,然後用剩下的引數繼續生成 tuple並繼承,是一種遞迴的思想

有了 tuple 就要有 get(),這個就更比較繞了,首先是需要類似的方式實現獲得 tuple 的值型別與元組型別,然後通過強制型別轉換,獲取對應的層級的 value

接下來是 bind,首先要解決的就是如何儲存建立時的引數列表,這裡就用到 tuple 來儲存了

奇技淫巧還是執行函式時取相應的元組的對應位置的值,還是類似的方式,通過特化模板,公式是 <n,indexs...> => <n - 1,n - 1,indexs...>,比如 3 最後會生成 0 0 1 2 那麼拋棄第一個,並用來展開元組,傳遞給函式指標

最重要的來了,就是如何實現 placeholders,簡單來說就是在上一步的 operator() 增加傳入引數,並製造成元組 r_args,然後帶進一個 _unwrap_tuple 類,這裡會過載 operator[] 根據傳入資料結構,如果是 _placeholders<index> 那麼取 r_args 相應的 index 位置,否則會直接 return

程式碼

不多說,還是直接放程式碼,僅作為參考,有寫的不好的地方輕噴

/*
 * Author: SpringHack - [email protected]
 * Last modified: 2020-02-19 10:16:17
 * Filename: main.cpp
 * Description: Created by SpringHack using vim automatically.
 */
#include <iostream>

namespace dosk { // begin namespace dosk

// function
template <typename... T>
class function;

template <typename Result,typename... Args>
class function<Result(Args...)> {
 private:
  Result (*function_)(Args...);
 public:
  typedef Result return_type;
  function() = default;
  function(Result (*fn)(Args...)) : function_(fn) {};
  Result operator()(Args... a) {
   return function_(a...);
  }
  function& operator=(Result (*fn)(Args...)) {
   function_ = fn;
   return *this;
  }
};

// tuple
template <typename... T>
class tuple;

template <typename HEAD,typename... LIST>
class tuple<HEAD,LIST...> : public tuple<LIST...> {
 public:
  HEAD value;
  tuple(HEAD head,LIST... list) : tuple<LIST...>(list...),value(head) {};
};

template <>
class tuple<> {};

// tuple get
template <int index,typename... T>
class _tuple_type;

template <int index,typename HEAD,typename... LIST>
class _tuple_type<index,tuple<HEAD,LIST...>> {
 public:
  typedef typename _tuple_type<index - 1,tuple<LIST...>>::value_type value_type;
  typedef typename _tuple_type<index - 1,tuple<LIST...>>::tuple_type tuple_type;
};

template <typename HEAD,typename... LIST>
class _tuple_type<0,LIST...>> {
 public:
  typedef HEAD value_type;
  typedef tuple<HEAD,LIST...> tuple_type;
};

template <int index,typename... LIST>
typename _tuple_type<index,LIST...>>::value_type get(tuple<HEAD,LIST...> t) {
 typedef typename _tuple_type<index,LIST...>>::value_type value_type;
 typedef typename _tuple_type<index,LIST...>>::tuple_type tuple_type;
 value_type rv = ((tuple_type)t).value;
 return rv;
}

// bind
template <size_t...>
class _tuple_index {};

template <size_t n,size_t... indexs>
class _make_indexs : public _make_indexs<n - 1,indexs...> {};

template<size_t... indexs>
class _make_indexs<0,indexs...> {
 public:
  typedef _tuple_index<indexs...> index_type;
};

namespace placeholders {

template <size_t index>
class _placeholders {};

_placeholders<0> _1;
_placeholders<1> _2;
_placeholders<2> _3;
_placeholders<3> _4;
_placeholders<4> _5;
_placeholders<5> _6;
_placeholders<6> _7;
_placeholders<7> _8;
_placeholders<8> _9;
_placeholders<9> _10;

template <typename... RArgs>
class _unwrap_tuple {
 public:
  tuple<RArgs...> r_args; 
  _unwrap_tuple(tuple<RArgs...> r_args) : r_args(r_args) {};
  template <typename R>
  R operator[](R r) {
   return r;
  }
  template <size_t index>
  auto operator[](placeholders::_placeholders<index>) {
   return get<index>(r_args);
  }
};

};

template <typename Func,typename... Args>
class bind_t {
 public:
  typedef typename _make_indexs<sizeof...(Args)>::index_type _indexs;
  typedef typename Func::return_type return_type;
  Func func;
  tuple<Args...> args;
  bind_t(Func func,Args... args): func(func),args(args...) {}
  template <typename... RArgs>
  return_type operator()(RArgs&&... _r_args) {
   tuple<RArgs...> r_args = tuple<RArgs...>(_r_args...);
   return run(_indexs(),r_args);
  }
  template <size_t... Idx,typename... RArgs>
  return_type run(_tuple_index<Idx...>,tuple<RArgs...> r_args) {
   return func(unwrap_args<Idx>(r_args)...);
  }
  template <size_t index,typename... RArgs>
  auto unwrap_args(tuple<RArgs...> r_args) {
   placeholders::_unwrap_tuple<RArgs...> _u_a(r_args);
   auto _m_a = get<index>(args);
   return _u_a[_m_a];
  }
};

template <typename Func,typename... Args>
bind_t<Func,Args...> bind(Func& func,Args&&... args) {
 return bind_t<Func,Args...>(func,args...);
}

}; // end namespace dosk



// Test code
std::string test_func(int a,const char * b) {
 return std::to_string(a) + std::string(b);
}

std::string test_bind_args(int a,int b,int c,int d,int e) {
 return std::to_string(a) + std::to_string(b) + std::to_string(c) + std::to_string(d) + std::to_string(e);
}

int main() {
 // Test tuple
 dosk::tuple<int,const char *> t(123,"456");
 std::cout << dosk::get<0>(t) << dosk::get<1>(t) << std::endl;
 // Test function
 dosk::function<std::string(int,const char *)> closure_1 = test_func;
 std::cout << closure_1(123,"456") << std::endl;
 // Test bind
 dosk::function<std::string(int,int,int)> closure_2 = test_bind_args;
 auto binder = dosk::bind(closure_2,1,dosk::placeholders::_2,3,dosk::placeholders::_1,5);
 std::cout << binder(4,2,0) << std::endl;
 return 0;
}

到此這篇關於C++ STL 內 std::{bind/tuple/function} 簡單實現的文章就介紹到這了,更多相關C++ std::{bind/tuple/function}內容請搜素我們以前的文章或下面相關文章,希望大家以後多多支援我們!