How to implement an easy_bind() that automagically inserts implied placeholders?

后端 未结 2 1564
故里飘歌
故里飘歌 2020-12-05 12:16

I recently found this nifty snippet on the web - it allows you to bind without having to pass in explicit placeholders:

template 

        
相关标签:
2条回答
  • 2020-12-05 12:57

    This was troubling me a lot, since I had to bind a function in a situation when I did not know the arguments at the time. (A factory such as shown here How to implement serialization in C++)

    For example (assume TSubClass::create is static)

    template<typename TFactoryClass, typename TArgs...>
    class Factory
    {
    public:
        template<typename TSubClass>
        void register(int id)
        {
             _map.insert(std::make_pair(id, std::bind(&TClass::create, /*how to give TArgs as placeholders??*/)));
        }
    }
    

    instead I was able to replace the std::bind with a lambda expression without having to use all these helper classes!

    template<typename TFactoryClass, typename TArgs...>
    class Factory
    {
    public:
        template<typename TSubClass>
        void register(int id)
        {
             _map.insert(std::make_pair(id, [](TArgs... args) { TSubClass::create(args...); }));
        }
    }
    

    as a bonus, you can also "bind" to constructors with this mechanism

    0 讨论(0)
  • 2020-12-05 13:02

    With the indices trick and the ability to tell std::bind about your own placeholder types, here's what I came up with:

    #include <functional>
    #include <type_traits>
    #include <utility>
    
    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 F, class... Args>
    auto easy_bind(indices<Is...>, F const& f, Args&&... args)
      -> decltype(std::bind(f, std::forward<Args>(args)..., placeholder<Is + 1>{}...))
    {
        return std::bind(f, std::forward<Args>(args)..., placeholder<Is + 1>{}...);
    }
    } // detail::
    
    template<class R, class... FArgs, class... Args>
    auto easy_bind(std::function<R(FArgs...)> const& f, Args&&... args)
        -> decltype(detail::easy_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, std::forward<Args>(args)...))
    {
        return detail::easy_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, std::forward<Args>(args)...);
    }
    

    Live example.

    Take note that I require the function argument to easy_bind to be either of type std::function, or convertible to it, so that I have a definite signature available.

    0 讨论(0)
提交回复
热议问题