Variadic templates and std::bind

后端 未结 2 1118
南方客
南方客 2020-12-08 08:53

Given the following templated function, how can I change it to take advantage of variadic templates? That is to say, to replace std::bind placeholders with a variadic param

相关标签:
2条回答
  • 2020-12-08 09:19

    You can (partially) specialize std::is_placeholder for specializations of a custom template. This way, you can introduce a placeholder generator via the usual int_sequence technique.

    From [func.bind.isplace]/2

    The implementation shall provide a definition that has the BaseCharacteristic of integral_constant<int, J> if T is the type of std::placeholders::_J, otherwise it shall have a BaseCharacteristic of integral_constant<int, 0>. A program may specialize this template for a user-defined type T to have a BaseCharacteristic of integral_constant<int, N> with N > 0 to indicate that T should be treated as a placeholder type.

    The usual int_sequence:

    #include <cstddef>
    
    template<int...> struct int_sequence {};
    
    template<int N, int... Is> struct make_int_sequence
        : make_int_sequence<N-1, N-1, Is...> {};
    template<int... Is> struct make_int_sequence<0, Is...>
        : int_sequence<Is...> {};
    

    The custom placeholder template and specialization of is_placeholder:

    template<int> // begin with 0 here!
    struct placeholder_template
    {};
    
    #include <functional>
    #include <type_traits>
    
    namespace std
    {
        template<int N>
        struct is_placeholder< placeholder_template<N> >
            : integral_constant<int, N+1> // the one is important
        {};
    }
    

    I'm not sure where to introduce the 1; the places I considered are all not optimal.

    Using it to write some binder:

    template<class Ret, class... Args, int... Is>
    void my_bind(Ret (*p)(Args...), int_sequence<Is...>)
    {
        auto x = std::bind(p, placeholder_template<Is>{}...);
        x( Args(42)... );
    }
    
    template<class Ret, class... Args>
    void my_bind(Ret (*p)(Args...))
    {
        my_bind(p, make_int_sequence< sizeof...(Args) >{});
    }
    

    Usage example of the binder:

    #include <iostream>
    
    void foo(double, char, int) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
    void bar(bool, short) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
    
    int main()
    {
        my_bind(foo);
        my_bind(bar);
    }
    
    0 讨论(0)
  • 2020-12-08 09:33

    I would like to propose a more simple solution to the problem to bind a member function to a variable number of placeholders:

    template<typename R, typename T, typename U, typename... Args>
    std::function<R(Args...)> Attach(R (T::*f)(Args...), U p)
    {
        return [p,f](Args... args)->R { return (p->*f)(args...); };
    };
    
    

    A simple example of the usage looks like that

    class CrazyAdd
    {
    public:
    
        CrazyAdd(double val)
        : m_crazyPart(val)
        {}
    
        double add(double a, double b)
        {
            return a+b+m_crazyPart;
        }
    
    private:
        double m_crazyPart;
    };
    
    void main() {
    
        CrazyAdd myAdd(39);
    
        // Create a function object that is bound to myAdd
        auto f = Attach(&CrazyAdd::add, &myAdd);
    
        // Call the function with the parameters    
        std::cout << f(1,2) << std::endl;   // outputs 42
    }
    
    

    Personally I think that's another good example why Scott Meyer recommends lambdas instead of std::bind.

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