如何实现一个自动插入隐含占位符的easy_bind()? *有会员指针*

时间:2015-03-15 06:09:28

标签: c++ templates c++11 stl variadic-templates

我遇到了这个有趣的解决方案(here和一个示例here)来创建一个std :: bind类型函数,而不必显式放置占位符。

任务

实现类似的绑定函数,但不能在绑定调用中放置值(我不需要它。)并添加调用此新绑定函数绑定成员指针的功能。

我设法做什么

所以我想出了如何使用虚拟std ::函数来获取函数的签名 我还想出了如何删除向bin调用添加值的功能。

所以这是我的代码:

#include <functional>
#include <type_traits>
#include <utility>

template <std::size_t... Is>
struct indices {};

template <std::size_t N, std::size_t... Is>
struct build_indices
  : build_indices<N-1, N-1, Is...> {};

template <std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...> {};

template<int I> struct placeholder{};

namespace std{
template<int I>
struct is_placeholder< ::placeholder<I>> : std::integral_constant<int, I>{};
} // std::
namespace detail{
    template<std::size_t... Is, class Fn, class... Args>
    auto my_bind(indices<Is...>, Fn const &f, Fn *i, Args&&... args) 
        -> decltype(std::bind(f, &i, std::forward<Args>(args)..., placeholder<1 + Is>{}...)){
        return std::bind(f, &i, std::forward<Args>(args)..., placeholder<1 + Is>{}...);
    }
}

template<class Ret, class... FArgs, class Fn, class... Args>
auto my_bind(std::function<Ret(FArgs...)>, Fn const&f, Fn *i, Args&&... args) 
        -> decltype(detail::my_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, &i, std::forward<Args>(args)...)){

    return detail::my_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, &i, std::forward<Args>(args)...);
}


#include <iostream>
struct tmp{
    void testt(int var1, int var2){
        std::cout << var1 << " " << var2 << std::endl;
    }
};

int main(){

    tmp TMP;
    auto f3 = my_bind(std::function<void(int, int)>(), &tmp::testt, &TMP);
    f3(22, 23);

}  

问题

我试图将成员指针传递给模板但是我遇到了编译器错误。 (问题似乎与成员指针的传递有关)我尝试了传递成员指针的其他方法,如描述herehere但是我没有使用这些方法取得任何进展。

以下是错误:

g++ -std=c++11 -Wall -W -pedantic -O2 hello-cpp-world.cc -o hello-cpp-world
hello-cpp-world.cc: In function ‘int main()’:
hello-cpp-world.cc:68:73: error: no matching function for call to ‘my_bind(std::function<void(int, int)>, void (tmp::*)(int, int), tmp*)’
     auto f3 = my_bind(std::function<void(int, int)>(), &tmp::testt, &TMP);
                                                                         ^
hello-cpp-world.cc:68:73: note: candidate is:
hello-cpp-world.cc:48:6: note: template<class Ret, class ... FArgs, class Fn, class ... Args> decltype (detail::my_bind(build_indices<(sizeof (FArgs ...) - sizeof (Args ...))>{}, f, (& i), (forward<Args>)(my_bind::args)...)) my_bind(std::function<_Res(_ArgTypes ...)>, const Fn&, Fn*, Args&& ...)
 auto my_bind(std::function<Ret(FArgs...)>, Fn const&f, Fn *i, Args&&... args) -> decltype(detail::my_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, &i, std::forward<Args>(args)...)){
      ^
hello-cpp-world.cc:48:6: note:   template argument deduction/substitution failed:
hello-cpp-world.cc:68:73: note:   deduced conflicting types for parameter ‘Fn’ (‘void (tmp::*)(int, int)’ and ‘tmp’)
     auto f3 = my_bind(std::function<void(int, int)>(), &tmp::testt, &TMP);
                                                                         ^
make: *** [hello-cpp-world] Error 1

问题

  • 我想要实现的目标是什么? (虽然我很确定)
  • 如果是的话,如何解决?

1 个答案:

答案 0 :(得分:2)

您的代码有两个关键问题:

  1. 您继续获取要作为成员函数调用的对象的地址。一旦实体成为指针,获取它的地址就不会对你有好处。
  2. 成员函数指针及其第一个参数明显具有不同的类型。要么您需要提供它的正确签名,您要从成员函数指针类型中提取第一个参数类型,或者保留相应的参数类型不受约束并使类型系统排序无效使用。后一种方法还具有可以传递引用和智能指针的优点。
  3. 以下是代码的修补版本,可以编译:

    #include <functional>
    #include <type_traits>
    #include <utility>
    
    template <std::size_t... Is>
    struct indices {};
    
    template <std::size_t N, std::size_t... Is>
    struct build_indices
      : build_indices<N-1, N-1, Is...> {};
    
    template <std::size_t... Is>
    struct build_indices<0, Is...> : indices<Is...> {};
    
    template<int I> struct placeholder{};
    
    namespace std{
    template<int I>
    struct is_placeholder< ::placeholder<I>> : std::integral_constant<int, I>{};
    } // std::
    namespace detail{
        template<std::size_t... Is, class Ret, class Fn, class... MArgs, class... Args>
        auto my_bind(indices<Is...>, Ret (Fn::*f)(MArgs...), Fn *i, Args&&... args) 
            -> decltype(std::bind(f, i, std::forward<Args>(args)..., placeholder<1 + Is>{}...)){
            return std::bind(f, i, std::forward<Args>(args)..., placeholder<1 + Is>{}...);
        }
    }
    
    template<class Ret, class... FArgs, class Fn, class... MArgs, class... Args>
    auto my_bind(std::function<Ret(FArgs...)>, Ret (Fn::*f)(MArgs...), Fn *i, Args&&... args) 
            -> decltype(detail::my_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, i, std::forward<Args>(args)...)){
    
        return detail::my_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, i, std::forward<Args>(args)...);
    }
    
    
    #include <iostream>
    struct tmp{
        void testt(int var1, int var2){
            std::cout << var1 << " " << var2 << std::endl;
        }
    };
    
    int main(){
    
        tmp TMP;
        auto f3 = my_bind(std::function<void(int, int)>(), &tmp::testt, &TMP);
        f3(22, 23);
    
    }