C++ STL 內(nèi) std::{bind/tuple/function} 簡單實現(xiàn)
基本邏輯思考
首先是實現(xiàn) function,這個比較簡單,重載 operator() 就好,這里只實現(xiàn)對函數(shù)指針的包裝
其次是實現(xiàn) tuple,這個會比較繞,通過模板取第一個參數(shù),然后用剩下的參數(shù)繼續(xù)生成 tuple并繼承,是一種遞歸的思想
有了 tuple 就要有 get(),這個就更比較繞了,首先是需要類似的方式實現(xiàn)獲得 tuple 的值類型與元組類型,然后通過強制類型轉(zhuǎn)換,獲取對應(yīng)的層級的 value
接下來是 bind,首先要解決的就是如何保存創(chuàng)建時的參數(shù)列表,這里就用到 tuple 來保存了
奇技淫巧還是運行函數(shù)時取相應(yīng)的元組的對應(yīng)位置的值,還是類似的方式,通過特化模板,公式是 <n, indexs...> => <n - 1, n - 1, indexs...>,比如 3 最后會生成 0 0 1 2 那么拋棄第一個,并用來展開元組,傳遞給函數(shù)指針
最重要的來了,就是如何實現(xiàn) placeholders,簡單來說就是在上一步的 operator() 增加傳入?yún)?shù),并制造成元組 r_args,然后帶進一個 _unwrap_tuple 類,這里會重載 operator[] 根據(jù)傳入數(shù)據(jù)結(jié)構(gòu),如果是 _placeholders<index> 那么取 r_args 相應(yīng)的 index 位置,否則會直接 return
代碼
不多說,還是直接放代碼,僅作為參考,有寫的不好的地方輕噴
/*
* Author: SpringHack - springhack@live.cn
* 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, tuple<HEAD, LIST...>> {
public:
typedef HEAD value_type;
typedef tuple<HEAD, LIST...> tuple_type;
};
template <int index, typename HEAD, typename... LIST>
typename _tuple_type<index, tuple<HEAD, LIST...>>::value_type get(tuple<HEAD, LIST...> t) {
typedef typename _tuple_type<index, tuple<HEAD, LIST...>>::value_type value_type;
typedef typename _tuple_type<index, tuple<HEAD, 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, 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, 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;
}
到此這篇關(guān)于C++ STL 內(nèi) std::{bind/tuple/function} 簡單實現(xiàn)的文章就介紹到這了,更多相關(guān)C++ std::{bind/tuple/function}內(nèi)容請搜素腳本之家以前的文章或下面相關(guān)文章,希望大家以后多多支持腳本之家!

