山寨一个std::bindoost::bind

这里是最初始的版本,参考https://github.com/cplusplus-study/fork_stl/blob/master/include/bind.hpp 提供了最简洁的实现方式。

第一部分是bind的实现代码, 第二部分是测试代码, 对bind的实现代码中有疑问或不明白的,可参考测试代码, 测试代码基本说明了某个代码的基本含义和用途。

1. 实现

  1 ///////////////////////////////////////////////////////////////////////////////
  2 // std::bindoost::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;
}
原文地址:https://www.cnblogs.com/xusd-null/p/3693817.html