4

I want to implement a class FuncWrapper which behaves like below, but I find it is not so easy as expected.

int OrdinaryFunction(int n)
{
    return n;
}

struct Functor
{
    int operator ()(int n)
    {
        return n;
    }
};

int main()
{
    FuncWrapper<int(int)> f1(OrdinaryFunction);
    cout << f1(1); // output 1;

    Functor functor;
    FuncWrapper<int(int)> f2(functor);
    cout << f2(2); // output 2;

    return 0;
}

My question is: How to implement the class FuncWrapper in PURE C++ (i.e, no STL) for making the code compiled?

I have partially implamented FuncWrapper showed below:

template<class T>
class FuncWrapper;

template<class ReturnType, class Parameter1>
class FuncWrapper<ReturnType(Parameter1)>
{
public:
    typedef ReturnType (*FunctionPtr)(Parameter1);

    template<class Functor>
    FuncWrapper(Functor fn) 
    {
        // ???
    }

    FuncWrapper(FunctionPtr fn)
        : fn(fn)
    {}

    ReturnType operator ()(Parameter1 p1)
    {
          return this->fn(p1);          
    }

private:
    FunctionPtr fn;
};
xmllmx
  • 39,765
  • 26
  • 162
  • 323
  • 4
    With [type erasure](http://stackoverflow.com/questions/5450159/type-erasure-techniques) – R. Martinho Fernandes Nov 05 '12 at 16:26
  • @Nicol, it is enough to make the code compiled. – xmllmx Nov 05 '12 at 16:29
  • Look at [std::ptr_fun](http://www.cplusplus.com/reference/std/functional/ptr_fun/). – Olaf Dietsche Nov 05 '12 at 16:29
  • @Olaf, ptr_fun is easy to implement. But I feel hard to make FuncWrapper accept both of function pointers and functors. – xmllmx Nov 05 '12 at 16:34
  • 3
    `template using FuncWrapper = std::function;` – Xeo Nov 05 '12 at 16:35
  • @Xeo, any stl is not allowed, or just stl::function is enough. – xmllmx Nov 05 '12 at 16:40
  • @xmllmx: "*it is enough to make the code compiled.*" That doesn't answer the question. – Nicol Bolas Nov 05 '12 at 16:59
  • 3
    @xmllmx: "*any stl is not allowed, or just stl::function is enough.*" `std::function` (note how that's spelled: st**d**, not st**l**) is not "STL". It's part of the C++ standard library. If you're not allowed to use the C++ standard library, then you need to say which parts of it you're not allowed to use. – Nicol Bolas Nov 05 '12 at 17:00
  • @Nicol, std::function is good for my question. But I want to know how to implement std::function. VC++'s source code is toooooo ugly to read, so I gave up. – xmllmx Nov 05 '12 at 17:03
  • @Nicol, I'm sorry for my mistakes. I indeed confused "stl" and "std". Thank you for your correction. – xmllmx Nov 05 '12 at 17:05
  • What he means is how this is implemented. Like suppose he is a vendor who has to implement the standard library. What C++ technique can be used to implement std::function... – CashCow Nov 05 '12 at 17:11

2 Answers2

4

Ok, you might think it is simple to do what you are trying, but it is very complicated.

In your case you want to be able to add a functor as well as an actual function and that is what complicates things. After all, if your class takes a constructor to a functor called Functor, where will you store the object?

One method, used by boost in its shared pointer class to store the deleter, is to actually have a base class and a derived class. Your constructor will construct an object (with new) that derives from the base class, and then you use polymorphism to invoke.

boost uses all sorts of clever techniques in its function and binder / mpl libraries but for now I would suggest you use this one.

If you are really against using boost or any kind of shared pointer you will have to manage the memory for this object. (Annoying because you want your outer class to be copyable and assignable).

I am going to make it simple and say I can use shared_ptr. I am also going to simplify the signature for now.

As an outline...

template< typename R, typename P > class FunctorBase
{
 public:
      virtual ~FunctorBase() {}
      virtual R call(P p) = 0;
};

template< typename R, typename P > class FunctionWrapper
{
     shared_ptr< FunctorBase< R, P > > impl;
  public:
     template< typename F > // a functor
     FunctionWrapper( Functor f )
     {
          // create appropriate impl for functors
     }

     FunctionWrapper( (R (func*)(P) )
     {
          // create appropriate impl for functions
     }

     R operator()( P p )
     {
          return impl->call(p);
     }
};

Your functor implementation could be something like:

template< typename R, typename P, typename F >
class FunctorImpl : public FunctorBase< R, P >
{
    F f;

   public: 
     FunctorImpl( F fparam ) : f( fparam )
     {
     }

     R call( P p )
     {
        return f( p );
     }
};

So now you see where you can store the functor..

CashCow
  • 30,981
  • 5
  • 61
  • 92
0

Just add to your functor a constructor that accepts pointer to a function (with the function signature that you want). Store the pointer in the functor and execute the pointed function from operator ().

If I understand you correctly, you want a wrapper that will expose a function-like behavior for both functors and functions. Store pointer to a functor in your wrapper instead of pointer to a function. Constructor with functor as a param will store the functor inside. Constructor with func as a param will create a functor (like I wrote in the answer) and store it inside.

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
SomeWittyUsername
  • 18,025
  • 3
  • 42
  • 85
  • I tried your method but failed. Because I don't know where to store the type of the Functor, which is necessary when calling operator (). – xmllmx Nov 05 '12 at 16:39
  • Please review my revised post. – xmllmx Nov 05 '12 at 16:47
  • Ok, if I understand you correctly, you want a wrapper that will expose a function-like behavior for both functors and functions. Store pointer to a functor in your wrapper instead of pointer to a function. Constructor with functor as a param will store the functor inside. Constructor with func as a param will create a functor (like I wrote in the answer) and store it inside. – SomeWittyUsername Nov 05 '12 at 17:01
  • could you give me a compilable class of FuncWrapper? Thanks in advance. – xmllmx Nov 05 '12 at 17:08
  • I downvoted because the OP wants to know how to do type-erasure and the answer didn't remotely address that. However, I saw your comment, so edited that into the answer, and removed the downvote. – Mooing Duck Nov 05 '12 at 17:15