using std::function, std::bind, perfect forwarding

Discussion in 'C++' started by Andrew Tomazos, Dec 23, 2011.

  1. I want to write a class that will wrap an arbitrary function and bind
    a set of arguments to it so that I can execute it later (perhaps in
    another thread, perhaps repeatedly):

    void f(const A& a) { ... }

    int main()
    {
    A a = ...;
    PFunction pf = MakeFunction(f,a);
    ...
    pf->call(); // executes f(a);
    }

    I've implemented something using std::function and std::bind, and it
    seems to work - but im having trouble getting the arguments to forward
    perfectly.

    The output of the below test program (which tracks the argument A) is:

    constructed at 0x7fff7f008d7f
    copied from 0x7fff7f008d7f to 0x7fff7f008a98 <----- HERE
    moved from 0x7fff7f008a98 to 0x20ce068
    desctructed at 0x7fff7f008a98
    desctructed at 0x7fff7f008d7f
    used at 0x20ce068
    desctructed at 0x20ce068

    Is there a way to modify MakeFunction and FunctionT (perhaps using
    std::forward or std::decay or something) such that the temporary A is
    moved into the Function object, and not copied?

    Thanks,
    Andrew.

    #include <iostream>
    #include <memory>
    #include <functional>

    using namespace std;

    class Function;

    typedef shared_ptr<Function> PFunction;

    class Function
    {
    public:
    virtual void call() = 0;
    };

    template<class F, class... Args>
    class FunctionT : public Function
    {
    public:
    FunctionT(F f, const Args&... args)
    : m_f(bind(f,args...))
    {}

    void call() { m_f(); }

    private:
    function<void()> m_f;
    };

    template<class F, class... Args>
    shared_ptr<Function> MakeFunction(F&& f, Args&&... args)
    {
    auto f2 = make_shared<FunctionT<F, Args...>>(f, args...);
    return dynamic_pointer_cast<Function> (f2);
    }

    class A
    {
    public:
    A()
    {
    cout << "constructed at " << this << endl;
    }

    A(const A& that)
    {
    cout << "copied from " << &that << " to " << this << endl;
    }

    A(A&& that)
    {
    cout << "moved from " << &that << " to " << this << endl;
    }

    ~A()
    {
    cout << "desctructed at " << this << endl;
    }
    };

    void f(const A& a)
    {
    cout << "used at " << &a << endl;
    }

    PFunction pf;

    void f1()
    {
    pf = MakeFunction(f, A());
    }

    void f2()
    {
    pf->call();
    }

    int main()
    {
    f1();
    f2();
    return 0;
    }
     
    Andrew Tomazos, Dec 23, 2011
    #1
    1. Advertising

  2. I figured it out. problem was I wasnt passing template parameter to
    std::forward (ie forward(args) instead of forward<Args>(args)).

    This version moves into place:

    class Function;

    typedef shared_ptr<Function> PFunction;

    class Function
    {
    public:
    virtual void call() = 0;
    virtual ~Function() {};
    };

    template<class F, class... Args>
    class FunctionT : public Function
    {
    public:
    FunctionT(const F& f, Args&&... args)
    : m_f(bind(f, forward<Args>(args)...))
    {}

    void call() { m_f(); }

    private:
    function<void()> m_f;
    };

    template<class F, class... Args>
    PFunction MakeFunction(F f, Args&&... args)
    {
    auto f2 = make_shared<FunctionT<F, Args...>>(f,
    forward<Args>(args)...);
    return dynamic_pointer_cast<Function> (f2);
    }

    -Andrew.

    On Dec 23, 10:51 am, Andrew Tomazos <> wrote:
    > I want to write a class that will wrap an arbitrary function and bind
    > a set of arguments to it so that I can execute it later (perhaps in
    > another thread, perhaps repeatedly):
    >
    >     void f(const A& a) { ... }
    >
    >     int main()
    >     {
    >         A a = ...;
    >         PFunction pf = MakeFunction(f,a);
    >         ...
    >         pf->call(); // executes f(a);
    >     }
    >
    > I've implemented something using std::function and std::bind, and it
    > seems to work - but im having trouble getting the arguments to forward
    > perfectly.
    >
    > The output of the below test program (which tracks the argument A) is:
    >
    >     constructed at 0x7fff7f008d7f
    >     copied from 0x7fff7f008d7f to 0x7fff7f008a98  <----- HERE
    >     moved from 0x7fff7f008a98 to 0x20ce068
    >     desctructed at 0x7fff7f008a98
    >     desctructed at 0x7fff7f008d7f
    >     used at 0x20ce068
    >     desctructed at 0x20ce068
    >
    > Is there a way to modify MakeFunction and FunctionT (perhaps using
    > std::forward or std::decay or something) such that the temporary A is
    > moved into the Function object, and not copied?
    >
    > Thanks,
    > Andrew.
    >
    > #include <iostream>
    > #include <memory>
    > #include <functional>
    >
    > using namespace std;
    >
    > class Function;
    >
    > typedef shared_ptr<Function> PFunction;
    >
    > class Function
    > {
    > public:
    >         virtual void call() = 0;
    >
    > };
    >
    > template<class F, class... Args>
    > class FunctionT : public Function
    > {
    > public:
    >         FunctionT(F f, const Args&... args)
    >                 : m_f(bind(f,args...))
    >         {}
    >
    >         void call() { m_f(); }
    >
    > private:
    >         function<void()> m_f;
    >
    > };
    >
    > template<class F, class... Args>
    > shared_ptr<Function> MakeFunction(F&& f, Args&&... args)
    > {
    >         auto f2 = make_shared<FunctionT<F, Args...>>(f, args...);
    >         return dynamic_pointer_cast<Function> (f2);
    >
    > }
    >
    > class A
    > {
    > public:
    >         A()
    >         {
    >                 cout << "constructed at " << this << endl;
    >         }
    >
    >         A(const A& that)
    >         {
    >                 cout << "copied from " << &that << " to "<< this << endl;
    >         }
    >
    >         A(A&& that)
    >         {
    >                 cout << "moved from " << &that << " to " << this << endl;
    >         }
    >
    >         ~A()
    >         {
    >                 cout << "desctructed at " << this << endl;
    >         }
    >
    > };
    >
    > void f(const A& a)
    > {
    >         cout << "used at " << &a << endl;
    >
    > }
    >
    > PFunction pf;
    >
    > void f1()
    > {
    >         pf = MakeFunction(f, A());
    >
    > }
    >
    > void f2()
    > {
    >         pf->call();
    >
    > }
    >
    > int main()
    > {
    >         f1();
    >         f2();
    >         return 0;
    >
    >
    >
    >
    >
    >
    >
    > }
     
    Andrew Tomazos, Dec 23, 2011
    #2
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Scott Meyers
    Replies:
    6
    Views:
    978
    Scott Meyers
    Dec 5, 2010
  2. Scott Meyers
    Replies:
    20
    Views:
    1,137
    itaj sherman
    Mar 16, 2011
  3. Alexis Nikichine

    Perfect function forwarding

    Alexis Nikichine, Dec 27, 2005, in forum: Javascript
    Replies:
    6
    Views:
    164
    Alexis Nikichine
    Dec 28, 2005
  4. dervih
    Replies:
    3
    Views:
    530
    dervih
    Jul 13, 2012
  5. Replies:
    3
    Views:
    348
Loading...

Share This Page