山寨一个std::bind\boost::bind

这里是最初始的版本,参考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;

}

 

 

你可能感兴趣的:(boost)