这里是最初始的版本,参考https://github.com/cplusplus-study/fork_stl/blob/master/include/bind.hpp 提供了最简洁的实现方式。
第一部分是bind的实现代码, 第二部分是测试代码, 对bind的实现代码中有疑问或不明白的,可参考测试代码, 测试代码基本说明了某个代码的基本含义和用途。
1. 实现
1 /////////////////////////////////////////////////////////////////////////////// 2 // std::bind\boost::bind的山寨版本, 主要学习用. 3 #include <stdlib.h> 4 #include <type_traits> 5 #include <utility> 6 #include <tuple> 7 #include <functional> 8 9 namespace xusd{ 10 template <int NUM> struct placeholder{ }; 11 12 template <typename T> struct is_placeholder; 13 template <int NUM> struct is_placeholder<placeholder<NUM> >{ enum{ value = NUM }; }; 14 template <typename T> struct is_placeholder{ enum{ value = 0 }; }; 15 16 template <int ...N> struct seq{ }; 17 template <unsigned N, unsigned...S> struct gen; 18 template <unsigned N, unsigned...S> struct gen: gen<N-1, N-1, S...>{ }; 19 template <unsigned...S> struct gen<0, S...>{ typedef seq<S...> type; }; 20 21 template <int N, typename B, typename C> 22 typename std::tuple_element< 23 N, 24 typename std::decay<B>::type 25 >::type 26 select(std::false_type, B&& b, C&& c){ 27 return std::get<N>(b); 28 } 29 30 template <int N, typename B, typename C> 31 typename std::tuple_element< 32 is_placeholder< 33 typename std::tuple_element< 34 N, 35 typename std::decay<B>::type 36 >::type 37 >::value ==0 ? 0 : 38 is_placeholder< 39 typename std::tuple_element< 40 N, 41 typename std::decay<B>::type 42 >::type 43 >::value - 1, 44 typename std::decay<C>::type 45 >::type 46 select(std::true_type, B&& b, C&& c) 47 { 48 return std::get< 49 is_placeholder< 50 typename std::tuple_element< 51 N, 52 typename std::decay<B>::type 53 >::type 54 >::value -1 55 >(c); 56 } 57 58 template <typename Fun> struct GetResult{ 59 typedef typename std::enable_if< 60 std::is_class< 61 typename std::decay<Fun>::type 62 >::value, 63 typename GetResult< 64 decltype(&Fun::operator()) 65 >::result_type 66 >::type result_type; 67 }; 68 69 template <typename R, typename... Args> 70 struct GetResult<R(Args...)>{ 71 typedef R result_type; 72 }; 73 template <typename C, typename R, typename... Args> 74 struct GetResult<R(C::*)(Args...)>{ 75 typedef R result_type; 76 }; 77 template <typename C, typename R, typename... Args> 78 struct GetResult<R(C::*)(Args...)const>{ 79 typedef R result_type; 80 }; 81 82 template <typename C, typename R> 83 struct GetResult<R(C::*)>{ 84 typedef decltype(((C*)0)->*((R(C::*))0)) result_type; 85 }; 86 87 template<typename F, typename... Args> 88 class bind_t { 89 typedef std::tuple<typename std::decay<Args>::type...> BindArgs; 90 typedef typename std::decay<F>::type CallFun; 91 enum class BindType { MemberFunction = 0, MemberObject = 1, Other = 2 }; 92 93 public: 94 typedef typename GetResult< 95 typename std::remove_pointer< 96 typename std::remove_reference<F>::type 97 >::type 98 >::result_type result_type; 99 100 bind_t(F fun, Args... args):_fun(fun), _bindArgs(args...){ } 101 102 template<typename... CArgs> 103 result_type operator()(CArgs&&... c){ 104 std::tuple<CArgs...> cargs(c...); 105 return callFunc( 106 std::integral_constant< 107 int, 108 std::is_member_function_pointer<CallFun>::value ? 0 : std::is_member_object_pointer<CallFun>::value ? 1 : 2 109 >(), 110 cargs, 111 typename gen< 112 std::tuple_size<BindArgs>::value - std::is_member_function_pointer<CallFun>::value 113 >::type() 114 ); 115 } 116 117 private: 118 template<typename T, int ...S> 119 result_type callFunc(std::integral_constant<int, 2>, T&& t, seq<S...>) { 120 return _fun( 121 select<S>( 122 std::integral_constant< 123 bool, 124 is_placeholder< 125 typename std::tuple_element<S, BindArgs>::type 126 >::value != 0 127 >(), 128 _bindArgs, 129 t)... 130 ); 131 } 132 133 template<typename T, int ...S> 134 result_type callFunc(std::integral_constant<int, 1>, T&& t, seq<S...>) { 135 return select<0>( 136 std::integral_constant< 137 bool, 138 is_placeholder< 139 typename std::tuple_element< 140 0, 141 BindArgs 142 >::type 143 >::value != 0 144 >(), 145 _bindArgs, 146 t)->*_fun; 147 } 148 149 template<typename T, int ...S> 150 result_type callFunc(std::integral_constant<int, 0>, T&& t, seq<S...>) { 151 return ( 152 select<0>( 153 std::integral_constant< 154 bool, 155 is_placeholder< 156 typename std::tuple_element< 157 0, 158 BindArgs 159 >::type 160 >::value != 0 161 >(), 162 _bindArgs, 163 t)->*_fun 164 ) 165 ( 166 select<S + 1>( 167 std::integral_constant< 168 bool, 169 is_placeholder< 170 typename std::tuple_element< 171 S + 1, 172 BindArgs 173 >::type 174 >::value != 0 175 >(), 176 _bindArgs, 177 t 178 )... 179 ); 180 } 181 182 private: 183 CallFun _fun; 184 BindArgs _bindArgs; 185 }; 186 187 template <typename F, typename... Args> 188 bind_t<typename std::decay<F>::type, typename std::decay<Args&&>::type...> 189 bind(F f, Args&&... args){ 190 return bind_t< 191 typename std::decay<F>::type, 192 typename std::decay<Args&&>::type... 193 >(f, args...); 194 } 195 196 extern placeholder<1> _1; 197 extern placeholder<2> _2; 198 extern placeholder<3> _3; 199 extern placeholder<4> _4; 200 extern placeholder<5> _5; 201 extern placeholder<6> _6; 202 extern placeholder<7> _7; 203 extern placeholder<8> _8; 204 extern placeholder<9> _9; 205 extern placeholder<10> _10; 206 extern placeholder<11> _11; 207 extern placeholder<12> _12; 208 extern placeholder<13> _13; 209 extern placeholder<14> _14; 210 extern placeholder<15> _15; 211 extern placeholder<16> _16; 212 extern placeholder<17> _17; 213 extern placeholder<18> _18; 214 extern placeholder<19> _19; 215 extern placeholder<20> _20; 216 extern placeholder<21> _21; 217 extern placeholder<22> _22; 218 extern placeholder<23> _23; 219 extern placeholder<24> _24; 220 }
2. 测试
/////////////////////////////////////////////////////////////////////////////// // 以下开始为测试代码. #include <cstdlib> #include <string> #include <iostream> #include <gtest/gtest.h> int add3(int x, int y, int z){ return x + y + z; } std::string to_string(std::string s1, std::string s2, std::string s3){ return s1 + s2 + s3; } int g_test_voidfun =0; void voidfun(){ g_test_voidfun = 1; } class MyTest{ public: std::string to_string(std::string s1, std::string s2, std::string s3){ return s1 + s2 + s3; } int add3(int x, int y, int z){ return x + y + z; } int cadd3(int x, int y, int z) const { return x + y + z; } void voidfun(){ g_test_voidfun = 2; } void constfun() const { g_test_voidfun = 3; } int memObj = 0; std::string memObj2; }; class TestAddFuncter{ public: int operator()(int x, int y){ return x + y; } }; TEST(TestSeq,Test1){ using namespace xusd; EXPECT_TRUE((std::is_same<gen<0>::type, seq<> >::value)); EXPECT_TRUE((std::is_same<gen<1>::type, seq<0> >::value)); EXPECT_TRUE((std::is_same<gen<2>::type, seq<0,1> >::value)); EXPECT_TRUE((std::is_same<gen<3>::type, seq<0,1,2> >::value)); EXPECT_TRUE((std::is_same<gen<4>::type, seq<0,1,2,3> >::value)); EXPECT_TRUE((std::is_same<gen<5>::type, seq<0,1,2,3,4> >::value)); EXPECT_TRUE((std::is_same<gen<6>::type, seq<0,1,2,3,4,5> >::value)); EXPECT_TRUE((std::is_same<gen<7>::type, seq<0,1,2,3,4,5,6> >::value)); EXPECT_TRUE((std::is_same<gen<8>::type, seq<0,1,2,3,4,5,6,7> >::value)); EXPECT_TRUE((std::is_same<gen<9>::type, seq<0,1,2,3,4,5,6,7,8> >::value)); EXPECT_TRUE((std::is_same<gen<10>::type, seq<0,1,2,3,4,5,6,7,8,9> >::value)); } TEST(TestPlaceHolder, Test1){ using namespace xusd; EXPECT_TRUE((std::is_same<decltype(_1), placeholder<1> >::value)); EXPECT_TRUE((std::is_same<decltype(_2), placeholder<2> >::value)); EXPECT_TRUE((std::is_same<decltype(_3), placeholder<3> >::value)); EXPECT_TRUE((std::is_same<decltype(_4), placeholder<4> >::value)); EXPECT_TRUE((std::is_same<decltype(_5), placeholder<5> >::value)); EXPECT_TRUE((std::is_same<decltype(_6), placeholder<6> >::value)); EXPECT_TRUE((std::is_same<decltype(_7), placeholder<7> >::value)); EXPECT_TRUE((std::is_same<decltype(_8), placeholder<8> >::value)); EXPECT_TRUE((std::is_same<decltype(_9), placeholder<9> >::value)); EXPECT_EQ(0, (is_placeholder<int>::value)); EXPECT_EQ(0, (is_placeholder<class A>::value)); EXPECT_EQ(1, (is_placeholder<decltype(_1)>::value)); EXPECT_EQ(2, (is_placeholder<decltype(_2)>::value)); EXPECT_EQ(3, (is_placeholder<decltype(_3)>::value)); EXPECT_EQ(4, (is_placeholder<decltype(_4)>::value)); EXPECT_EQ(5, (is_placeholder<decltype(_5)>::value)); EXPECT_EQ(6, (is_placeholder<decltype(_6)>::value)); EXPECT_EQ(7, (is_placeholder<decltype(_7)>::value)); EXPECT_EQ(8, (is_placeholder<decltype(_8)>::value)); EXPECT_EQ(9, (is_placeholder<decltype(_9)>::value)); } TEST(TestSelectArgs, Test1){ using namespace xusd; auto b = std::make_tuple(1,_1,2,_2,3,_3,4,_4); auto c = std::make_tuple(11,22,33,44); EXPECT_EQ(1, (select<0>(std::false_type(), b, c))); EXPECT_EQ(11, (select<1>(std::true_type(), b, c))); EXPECT_EQ(2, (select<2>(std::false_type(), b, c))); EXPECT_EQ(22, (select<3>(std::true_type(), b, c))); EXPECT_EQ(3, (select<4>(std::false_type(), b, c))); EXPECT_EQ(33, (select<5>(std::true_type(), b, c))); EXPECT_EQ(4, (select<6>(std::false_type(), b, c))); EXPECT_EQ(44, (select<7>(std::true_type(), b, c))); } TEST(TestGetResult, Test1){ using namespace xusd; class Ret; class C; class Args; class Mem; EXPECT_TRUE((std::is_same<void,xusd::GetResult<void()>::result_type>::value)); EXPECT_TRUE((std::is_same<int,xusd::GetResult<int(int)>::result_type>::value)); EXPECT_TRUE((std::is_same<const int,xusd::GetResult<const int()>::result_type>::value)); EXPECT_TRUE((std::is_same<Ret,xusd::GetResult<Ret(Args)>::result_type>::value)); EXPECT_TRUE((std::is_same<Ret,xusd::GetResult<Ret(C::*)(Args)>::result_type>::value)); EXPECT_TRUE((std::is_same<Mem&,xusd::GetResult<Mem(C::*)>::result_type>::value)); const MyTest t1; EXPECT_TRUE((std::is_same<int,decltype(t1.memObj)>::value)); } #define DT(x) decltype(x) TEST(TestBind_t, Test1){ using namespace xusd; EXPECT_TRUE((std::is_same<void, bind_t<void ()>::result_type>::value)); EXPECT_TRUE((std::is_same<void, bind_t<void (char), DT((_1))>::result_type>::value)); EXPECT_TRUE((std::is_same<void, bind_t<void (char,short), DT((_1)), DT((_2))>::result_type>::value)); EXPECT_TRUE((std::is_same<void, bind_t<void (char,short, int), DT((_1)), DT((_2)), DT((_3))>::result_type>::value)); EXPECT_TRUE((std::is_same<void, bind_t<void (char,short, int, long), DT((_1)), DT((_2)), DT((_3)), DT((_4))>::result_type>::value)); EXPECT_TRUE((std::is_same<void, bind_t<void (char,short, int, long, long long), DT((_1)), DT((_2)), DT((_3)), DT((_4)), DT((_5))>::result_type>::value)); EXPECT_TRUE((std::is_same<int, bind_t<int ()>::result_type>::value)); EXPECT_TRUE((std::is_same<int, bind_t<int (char), DT((_1))>::result_type>::value)); EXPECT_TRUE((std::is_same<int, bind_t<int (char,short), DT((_1)), DT((_2))>::result_type>::value)); EXPECT_TRUE((std::is_same<int, bind_t<int (char,short, int), DT((_1)), DT((_2)), DT((_3))>::result_type>::value)); EXPECT_TRUE((std::is_same<int, bind_t<int (char,short, int, long), DT((_1)), DT((_2)), DT((_3)), DT((_4))>::result_type>::value)); EXPECT_TRUE((std::is_same<int, bind_t<int (char,short, int, long, long long), DT((_1)), DT((_2)), DT((_3)), DT((_4)), DT((_5))>::result_type>::value)); EXPECT_TRUE((std::is_same<class AAA, bind_t<class AAA ()>::result_type>::value)); EXPECT_TRUE((std::is_same<class AAA, bind_t<class AAA (char), DT((_1))>::result_type>::value)); EXPECT_TRUE((std::is_same<class AAA, bind_t<class AAA (char,short), DT((_1)), DT((_2))>::result_type>::value)); EXPECT_TRUE((std::is_same<class AAA, bind_t<class AAA (char,short, int), DT((_1)), DT((_2)), DT((_3))>::result_type>::value)); EXPECT_TRUE((std::is_same<class AAA, bind_t<class AAA (char,short, int, long), DT((_1)), DT((_2)), DT((_3)), DT((_4))>::result_type>::value)); EXPECT_TRUE((std::is_same<class AAA, bind_t<class AAA (char,short, int, long, long long), DT((_1)), DT((_2)), DT((_3)), DT((_4)), DT((_5))>::result_type>::value)); EXPECT_TRUE((std::is_same<class AAA, bind_t<class AAA (class BBB), DT((_1))>::result_type>::value)); EXPECT_TRUE((std::is_same<class AAA, bind_t<class AAA (class BBB, class CCC), DT((_1))>::result_type>::value)); EXPECT_TRUE((std::is_same<class AAA, bind_t<class AAA (class BBB, class CCC, class DDD), DT((_1))>::result_type>::value)); EXPECT_TRUE((std::is_same<class AAA, bind_t<class AAA (class BBB, class CCC, class DDD, class EEE), DT((_1))>::result_type>::value)); EXPECT_TRUE((std::is_same<class AAA, bind_t<class AAA (class BBB, class CCC, class DDD, class EEE, class FFF), DT((_1))>::result_type>::value)); EXPECT_TRUE((std::is_same<class AAA, bind_t<class AAA (class BBB, class CCC, class DDD, class EEE, class FFF, class GGG), DT((_1))>::result_type>::value)); EXPECT_TRUE((std::is_same<class Ret, bind_t<class Ret (class Arg1), DT((_1))>::result_type>::value)); EXPECT_TRUE((std::is_same<class Ret, bind_t<class Ret (class Arg1, class Arg2), DT((_2)), DT((_1))>::result_type>::value)); EXPECT_TRUE((std::is_same<class Ret, bind_t<class Ret (class Arg1, class Arg2, class Arg3), DT((_2)), DT((_1))>::result_type>::value)); EXPECT_TRUE((std::is_same<class Ret, bind_t<class Ret (class Arg1, class Arg2, class Arg3, class Arg4),DT((_4)), DT((_1))>::result_type>::value)); EXPECT_TRUE((std::is_same<class Ret, bind_t<class Ret (class Arg1, class Arg2, class Arg3, class Arg4, class Arg5), DT((_5))>::result_type>::value)); EXPECT_TRUE((std::is_same<class Ret, bind_t<class Ret (class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6), DT((_6))>::result_type>::value)); } TEST(TestBind_t, Test2){ using namespace xusd; bind_t<int(int, int, int), DT(_3), DT(_2), DT(_1)> t1(add3, _3, _2, _1); EXPECT_EQ((add3(1, 2, 3)), (t1(1, 2, 3))); EXPECT_EQ((add3(0, 0, 0)), (t1(0, 0, 0))); bind_t<std::string(std::string, std::string, std::string), DT(_1), DT(_2), DT(_3)> s1(to_string, _1, _2, _3); bind_t<std::string(std::string, std::string, std::string), DT(_2), DT(_3), DT(_1)> s2(to_string, _2, _3, _1); bind_t<std::string(std::string, std::string, std::string), DT(_3), DT(_1), DT(_2)> s3(to_string, _3, _1, _2); EXPECT_EQ("123", (s1("1", "2", "3"))); EXPECT_EQ("321", (s1("3", "2", "1"))); EXPECT_EQ("23", (s1("", "2", "3"))); EXPECT_EQ("2_3", (s1("2", "_", "3"))); EXPECT_EQ("231", (s2("1", "2", "3"))); EXPECT_EQ("312", (s3("1", "2", "3"))); } TEST(TestBind, NotMemberFunction){ using namespace xusd; EXPECT_EQ((add3(1, 2, 3)), (xusd::bind(add3, _3, _2, _1)(1, 2, 3))); EXPECT_EQ((add3(0, 0, 0)), (xusd::bind(add3, _3, _2, _1)(0, 0, 0))); EXPECT_EQ("123", (xusd::bind(to_string, _1, _2, _3)("1", "2", "3"))); EXPECT_EQ("321", (xusd::bind(to_string, _1, _2, _3)("3", "2", "1"))); EXPECT_EQ("23", (xusd::bind(to_string, _1, _2, _3)("", "2", "3"))); EXPECT_EQ("2_3", (xusd::bind(to_string, _1, _2, _3)("2", "_", "3"))); EXPECT_EQ("231", (xusd::bind(to_string, _2, _3, _1)("1", "2", "3"))); EXPECT_EQ("312", (xusd::bind(to_string, _3, _1, _2)("1", "2", "3"))); bind((voidfun))(); EXPECT_EQ(g_test_voidfun, 1); } TEST(TestBind, PassToFunctional){ using namespace xusd; EXPECT_EQ("123", (std::function<std::string(std::string, std::string, std::string)>(xusd::bind(to_string, _1, _2, _3))("1", "2", "3"))); EXPECT_EQ("321", (std::function<std::string(std::string, std::string, std::string)>(xusd::bind(to_string, _1, _2, _3))("3", "2", "1"))); EXPECT_EQ("23", (std::function<std::string(std::string, std::string, std::string)>(xusd::bind(to_string, _1, _2, _3))("", "2", "3"))); EXPECT_EQ("2_3", (std::function<std::string(std::string, std::string, std::string)>(xusd::bind(to_string, _1, _2, _3))("2", "_", "3"))); EXPECT_EQ("231", (std::function<std::string(std::string, std::string, std::string)>(xusd::bind(to_string, _2, _3, _1))("1", "2", "3"))); EXPECT_EQ("312", (std::function<std::string(std::string, std::string, std::string)>(xusd::bind(to_string, _3, _1, _2))("1", "2", "3"))); } TEST(TestBind, TestMumberFunction){ using namespace xusd; MyTest test; EXPECT_EQ((add3(1, 2, 3)), (xusd::bind(&MyTest::add3, &test, _3, _2, _1)(1, 2, 3))); EXPECT_EQ((add3(0, 0, 0)), (xusd::bind(&MyTest::add3, &test, _3, _2, _1)(0, 0, 0))); EXPECT_EQ("123", (xusd::bind(&MyTest::to_string, &test, _1, _2, _3)("1", "2", "3"))); EXPECT_EQ("321", (xusd::bind(&MyTest::to_string, &test, _1, _2, _3)("3", "2", "1"))); EXPECT_EQ("23", (xusd::bind(&MyTest::to_string, &test, _1, _2, _3)("", "2", "3"))); EXPECT_EQ("2_3", (xusd::bind(&MyTest::to_string, &test, _1, _2, _3)("2", "_", "3"))); EXPECT_EQ("231", (xusd::bind(&MyTest::to_string, &test, _2, _3, _1)("1", "2", "3"))); EXPECT_EQ("312", (xusd::bind(&MyTest::to_string, &test, _3, _1, _2)("1", "2", "3"))); EXPECT_EQ("312", (xusd::bind(&MyTest::to_string, _4, _3, _1, _2)("1", "2", "3", &test))); xusd::bind(&MyTest::voidfun, &test)(); EXPECT_EQ(2, g_test_voidfun); xusd::bind(&MyTest::constfun, &test)(); EXPECT_EQ(3, g_test_voidfun); } TEST(TestBind, TestFuncter){ using namespace xusd; TestAddFuncter f1; EXPECT_EQ(3, (xusd::bind(f1, _1, _2)(2, 1))); } TEST(TestBind, TestCFunction){ using namespace xusd; EXPECT_EQ(1, (xusd::bind(abs, _1)(-1))); } TEST(TestBind, TestMemberObj){ MyTest t1; EXPECT_EQ(t1.memObj, 0); xusd::bind(&MyTest::memObj, &t1)() = 1; EXPECT_EQ(t1.memObj, 1); } int main(int argc, char* argv[]){ ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } namespace xusd{ placeholder<1> _1; placeholder<2> _2; placeholder<3> _3; placeholder<4> _4; placeholder<5> _5; placeholder<6> _6; placeholder<7> _7; placeholder<8> _8; placeholder<9> _9; placeholder<10> _10; placeholder<11> _11; placeholder<12> _12; placeholder<13> _13; placeholder<14> _14; placeholder<15> _15; placeholder<16> _16; placeholder<17> _17; placeholder<18> _18; placeholder<19> _19; placeholder<20> _20; placeholder<21> _21; placeholder<22> _22; placeholder<23> _23; placeholder<24> _24; }