Passing member function with all arguments to std::function

前端 未结 3 968
醉梦人生
醉梦人生 2020-12-24 15:52

How can I create a std::function from member function without need for typing std::placeholders::_1, std::placeholders::_2, etc - I would like to \"placehold\" all arguments

相关标签:
3条回答
  • 2020-12-24 16:18

    You can use function template which will deduce all member function parameter types, like this:

    template<typename Obj, typename Result, typename ...Args>
    auto make_delegate(const Obj &x, Result (Obj::*fun)(Args...)) -> // ...
    

    And will return special delegate object, which will contain your object (or pointer to it) and just forward all passed arguments to member function of underlying object:

    template<typename Obj, typename Result, typename ...Args>
    struct Delegate
    {
        Obj x;
        Result (Obj::*f)(Args...);
    
        template<typename ...Ts>
        Result operator()(Ts&&... args)
        {
            return (x.*f)(forward<Ts>(args)...);
        }
    };
    

    You will get following usage syntax:

    function<int(int,float,bool)> fun = make_delegate(object, &Foo::bar);
    

    Here is full example:

    #include <functional>
    #include <iostream>
    #include <utility>
    
    using namespace std;
    
    struct Foo
    {
        int bar(int x, float y, bool z)
        {
            cout << "bar: " << x << " " << y << " " << z << endl;
            return 0;
        }
    };
    
    int baz(int x, float y, bool z)
    {
        cout << "baz: " << x << " " << y << " " << z << endl;
        return 0;
    }
    
    template<typename Obj, typename Result, typename ...Args>
    struct Delegate
    {
        Obj x;
        Result (Obj::*f)(Args...);
    
        template<typename ...Ts>
        Result operator()(Ts&&... args)
        {
            return (x.*f)(forward<Ts>(args)...);
        }
    };
    
    template<typename Obj, typename Result, typename ...Args>
    auto make_delegate(const Obj &x, Result (Obj::*fun)(Args...))
        -> Delegate<Obj, Result, Args...>
    {
        Delegate<Obj, Result, Args...> result{x, fun};
        return result;
    }
    
    int main()
    {
        Foo object;
        function<int(int,float,bool)> fun[] =
        {
            baz,
            make_delegate(object, &Foo::bar) // <---- usage
        };
        for(auto &x : fun)
            x(1, 1.0, 1);
    }
    

    Output is:

    baz: 1 1 1
    bar: 1 1 1
    

    Live Demo on Coliru

    0 讨论(0)
  • 2020-12-24 16:18

    If you don't want to use placeholders, then std::bind is not for you:

    Use lambda:

    Foo object;
    
    std::function<int(int,float,bool)> fun = [&object](int a, float b, bool c) {
            return object.bar(a,b,c);
    };
    

    You can capture object by value if you wish. Perhaps you realize this is no better than using placeholders, as you're typing parameters anyway — in fact you type more in this case!

    0 讨论(0)
  • 2020-12-24 16:24

    You can easily do this with variadic generic lambdas in C++14:

    template<typename F, typename C>
    auto smart_bind(F f, C* c)
    {
      return [c, f](auto&&... args) { return (c->*f)(std::forward<decltype(args)>(args)...); };
    }
    
    // In your code:
    std::function<int(int,float,bool)> fun2 = smart_bind(&Foo::bar, &object);
    

    Live demo: https://ideone.com/deR4fy

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