-1

I tried to use this code but it does not work with class member functions. Is there a way to generate a wrapper for class member function and call it like wrapper for non-class member?

#include <functional>
template <typename F>
class wrapper;

template <typename F, typename... Args>
typename std::result_of<F(Args...)>::type execute_helper (F&& f, Args&&... args) {
    return std::forward<F>(f)( std::forward<Args>(args)...);
}

template<typename Ret, typename... Args>
class wrapper <std::function<Ret(Args...)>>
{
    std::function<Ret(Args...)> m_f;
public:
    wrapper( std::function<Ret(Args...)> f ): m_f(f) {}
    Ret operator()(Args... args) const  { 
        return execute_helper (m_f, args...); 
    }
};
Twaik Yont
  • 102
  • 10
  • 1
    Why do you even need `execute_helper`? Just write out `m_f(args...)`. Also, why wouldn't this work for member functions (What is the exact error you are getting, and the piece of code that produces that error)? And what does this wrapper do that `std::function` doesn't? – Artyer Aug 04 '19 at 21:23

1 Answers1

2

The problem with member function is they need an object of the class to be called.

Supposing you can pass the object of the class, together with the pointer to the member function, to the constructor, I suppose you can write the wrapper as follows

template <typename Ret, typename Cl, typename ...Args>
class wrapper <Ret(Cl::*)(Args...)>
 {
   private:
      std::function<Ret(Args...)> m_f;

   public:
      wrapper (Cl cl, Ret(Cl::*m)(Args...))
         : m_f{ [=](Args... as) mutable { return (cl.*m)(as...); } }
          { }

      Ret operator() (Args... args) const
       { return m_f(args...); }
 };

The following is a full compilable example of use

#include <functional>
#include <iostream>

template <typename F>
class wrapper;

template <typename Ret, typename Cl, typename ...Args>
class wrapper <Ret(Cl::*)(Args...)>
 {
   private:
      std::function<Ret(Args...)> m_f;

   public:
      wrapper (Cl cl, Ret(Cl::*m)(Args...))
         : m_f{ [=](Args... as) mutable { return (cl.*m)(as...); } }
          { }

      Ret operator() (Args... args) const
       { return m_f(args...); }
 };

struct foo
 {
   long long bar (int a, long b, long long c)
    { return a+b+c; }
 };

int main ()
 {
   foo  f;

   wrapper<decltype(&foo::bar)>  wfb{f, &foo::bar};

   std::cout << wfb(1, 2l, 3ll) << std::endl;
 }

Observe that the example works for a not-const member functions.

For const member functions, you could need another wrapper

template <typename Ret, typename Cl, typename ...Args>
class wrapper <Ret(Cl::*)(Args...) const>
 {
   private:
      std::function<Ret(Args...)> m_f;

   public:
      wrapper (Cl const & cl, Ret(Cl::*m)(Args...) const)
         : m_f{ [=](Args... as) { return (cl.*m)(as...); } }
          { }

      Ret operator() (Args... args) const
       { return m_f(args...); }
 };

In both cases, you could improve a little the operator() adding perfect forwarding

  template <typename ... As>   
  Ret operator() (As && ... as) const
   { return m_f(std::forward<As>(as)...); } 
max66
  • 65,235
  • 10
  • 71
  • 111
  • Is there a way to modify this code to use it inside class definition? – Twaik Yont Aug 04 '19 at 22:01
  • @TwaikYont - sorry... I don't understand what do you mean. – max66 Aug 04 '19 at 22:02
  • I need to use wrappers inside class definition in *.hpp. – Twaik Yont Aug 04 '19 at 22:03
  • Something like class A : public B { wrapper<&B::foo> foo(&B::foo); } . I tried to write code using std::mem_fn and std::bind with placeholders but failed. – Twaik Yont Aug 04 '19 at 22:05
  • @TwaikYont - I suppose it's possible; but, in my example, you need also an object of type `B` initializing the wrapper. – max66 Aug 04 '19 at 22:07
  • Ok. I modified template to make it possible to declare wrappers outside function. But I have [https://gist.github.com/twaik/fca3c17307e160ea1cbbac9dcb435b04#file-gistfile2-txt](another problem). It has compile time errors while wrapper is declared inside class. Can you please help me? – Twaik Yont Aug 04 '19 at 23:00
  • @TwaikYont: You cannot use that syntax to initialize data member, you need `m{init}` or `m = init` instead of `m(init)` [Demo](http://coliru.stacked-crooked.com/a/bae8b6434729f16d). – Jarod42 Aug 05 '19 at 06:09
  • *"you could improve a little the operator() adding perfect forwarding"*. In fact, it would even be required for case as `void (C::*)(std::unique_ptr)`. 2 possibilities, template method (with SFINAE), or non template method and forwarding according to method signature (might produce extra move). – Jarod42 Aug 05 '19 at 06:15