Wrote by mutouyun. (http://orzz.org/cxx-bind/)
这篇文的草稿我是在2014年5月11号开始打的,可是拖拖拉拉直到现在才真正动笔写,自己对自己也是醉了。。
之所以写bind而不是什么其他的东西,是因为bind在各种C++的utility里面可以说是最能体现出“利用语言本身来拓展语言功能”这一特征的了。
在C++98/03的时代,人们为了让C++具有把函数和参数打包成闭包(closure)这一能力而发明了bind,从而使C++不仅可以存储算法执行的结果,还可以打包算法和算法的传入参数,存储算法执行的动作,直到调用这个闭包的时候才释放出参数并参与算法计算。有了这个东西之后,再配合可以存储任何可调用体的function对象,不少面向对象里麻烦的调用关系可以被简化到不像话的地步(具体可参看此文:以boost::function和boost:bind取代虚函数)。
在C++98/03下实现一个好用的bind是痛苦的。看看Boost.Bind,还有我自己,为了实现一个完善的bind折腾遍了C++的奇巧淫技……这是很划不来的,平时学习或兴趣玩一玩还可以,真在项目工程里这样做了,如何维护会是一个很头痛的事情。
在C++11里事情变得很不一样了。首先stl里就已经给我们提供了好用的std::bind,然后再就是语言本身的进化,让“写一个bind”之类的事情变得无比简单。于是我去年曾花了点时间,用C++11写了下面这个200多行的“simple bind”,用来让自己被C++98/03腌入味的思维习惯向C++11转换一下:
#include <type_traits>
#include <tuple>
#include <utility>
namespace simple {
/*
Placeholder
*/
template <int N>
struct placeholder {};
const placeholder<1> _1; const placeholder<6> _6; const placeholder<11> _11; const placeholder<16> _16;
const placeholder<2> _2; const placeholder<7> _7; const placeholder<12> _12; const placeholder<17> _17;
const placeholder<3> _3; const placeholder<8> _8; const placeholder<13> _13; const placeholder<18> _18;
const placeholder<4> _4; const placeholder<9> _9; const placeholder<14> _14; const placeholder<19> _19;
const placeholder<5> _5; const placeholder<10> _10; const placeholder<15> _15; const placeholder<20> _20;
/*
Sequence & Generater
*/
template <int... N>
struct seq { typedef seq<N..., sizeof...(N)> next_type; };
template <typename... P>
struct gen;
template <>
struct gen<>
{
typedef seq<> seq_type;
};
template <typename P1, typename... P>
struct gen<P1, P...>
{
typedef typename gen<P...>::seq_type::next_type seq_type;
};
/*
Merge the type of tuple
*/
template <typename T, typename TupleT>
struct tuple_insert;
template <typename T, typename... TypesT>
struct tuple_insert<T, std::tuple<TypesT...>>
{
typedef std::tuple<T, TypesT...> type;
};
template <class TupleT, typename... BindT>
struct merge;
template <typename... ParsT>
struct merge<std::tuple<ParsT...>>
{
typedef std::tuple<> type;
};
template <typename... ParsT, typename B1, typename... BindT>
struct merge<std::tuple<ParsT...>, B1, BindT...>
{
typedef std::tuple<ParsT...> tp_t;
typedef typename tuple_insert<
B1,
typename merge<tp_t, BindT...>::type
>::type type;
};
template <typename... ParsT, int N, typename... BindT>
struct merge<std::tuple<ParsT...>, const placeholder<N>&, BindT...>
{
typedef std::tuple<ParsT...> tp_t;
typedef typename tuple_insert<
typename std::tuple_element<N - 1, tp_t>::type,
typename merge<tp_t, BindT...>::type
>::type type;
};
/*
Select the value of tuple
*/
template <typename T, class TupleT>
inline auto select(TupleT& /*tp*/, T&& val) -> T&&
{
return std::forward<T>(val);
}
template <int N, class TupleT>
inline auto select(TupleT& tp, placeholder<N>) -> decltype(std::get<N - 1>(tp))
{
return std::get<N - 1>(tp);
}
/*
Return type traits
*/
template <typename F>
struct return_traits : return_traits<decltype(&F::operator())> {};
template <typename T>
struct return_traits<T*> : return_traits<T> {};
// check function
template <typename R, typename... P>
struct return_traits<R(*)(P...)> { typedef R type; };
// check member function
#define RESULT_TRAITS__(...) \
template <typename R, typename C, typename... P> \
struct return_traits<R(C::*)(P...) __VA_ARGS__> { typedef R type; };
RESULT_TRAITS__()
RESULT_TRAITS__(const)
RESULT_TRAITS__(volatile)
RESULT_TRAITS__(const volatile)
#undef RESULT_TRAITS__
/*
Type detect
*/
template <typename T>
struct is_pointer_noref
: std::is_pointer<typename std::remove_reference<T>::type>
{};
template <typename T>
struct is_memfunc_noref
: std::is_member_function_pointer<typename std::remove_reference<T>::type>
{};
template <typename T>
struct is_wrapper
: std::false_type
{};
template <typename T>
struct is_wrapper<std::reference_wrapper<T>>
: std::true_type
{};
template <typename T>
struct is_wrapper_noref
: is_wrapper<typename std::remove_reference<typename std::remove_cv<T>::type>::type>
{};
/*
The invoker for call a callable
*/
template <typename R, typename F, typename... P>
inline typename std::enable_if<is_pointer_noref<F>::value,
R>::type invoke(F&& f, P&&... args)
{
return (*std::forward<F>(f))(std::forward<P>(args)...);
}
template <typename R, typename F, typename P1, typename... P>
inline typename std::enable_if<is_memfunc_noref<F>::value &&
is_pointer_noref<P1>::value,
R>::type invoke(F&& f, P1&& this_ptr, P&&... args)
{
return (std::forward<P1>(this_ptr)->*std::forward<F>(f))(std::forward<P>(args)...);
}
template <typename R, typename F, typename P1, typename... P>
inline typename std::enable_if<is_memfunc_noref<F>::value &&
!is_pointer_noref<P1>::value && !is_wrapper_noref<P1>::value,
R>::type invoke(F&& f, P1&& this_obj, P&&... args)
{
return (std::forward<P1>(this_obj).*std::forward<F>(f))(std::forward<P>(args)...);
}
template <typenam