8

Imagine I have the following free function and functor:

void myFreeFunction(void)
{
    cout << "Executing free function" << endl;
}

struct MyFunctor
{
    void operator()(void)
    {
        cout << "Executing functor" << endl;
    }
};

As discribed by this answer, I can pass my function or functor as a template argument to another function:

template <typename F>
void doOperation(F f)
{
    f();
}

And then call:

doOperation(myFreeFunction);
doOperation(MyFunctor());

So far so good. But what if I want something like the following:

template<typename Callback>
class MyClass
{
private:
    Callback mCallback;

public:
    MyClass(){}

    void execute()
    {
        mCallback();
    }
};

In this case I'm specifing the function/functor when I declare the class but not calling it until later. It works for functors:

MyClass<MyFunctor> myClass1;
myClass1.execute();

But not for functions:

MyClass<myFreeFunction> myClass2;
myClass2.execute();

Compiler says:

error C2923: 'MyClass' : 'myFreeFunction' is not a valid template type argument for parameter 'Callback'

Which is fair enough... but how would you structure this?

Note: I'm aware of std::function and may end up using this. It's measurably slower though so I'm looking at all options.

Thanks,

David

Community
  • 1
  • 1
David Williams
  • 753
  • 1
  • 4
  • 11
  • using boost::bind() and boost::function(), you can accomplish what you are looking for. If interested, I can provide an example. – Lou Mar 02 '12 at 15:20
  • Thanks, but as noted at the end I'm already aware of std::function as a solution. It seems to have performance overhead though as a result of the function not being inlined. – David Williams Mar 02 '12 at 15:22

1 Answers1

9

The problem is that freefunction is not a type but a element of a of (int this case a function pointer.

to fix this problem you need to pass the function in, in construction, however you still need to know the exact type.

myclass<call_back_t> my_class(call_back);

EDIT: In c++11 the type can be got from decltype(call_back)

however getting the call back can be troublesome it is often a lot easier to create a generator function

//this should be in the namespace of the class or a static member of it
template<FuncType>
myclass<FuncType> make_class(FuncType func)
{
     return myclass<FuncType>(func);
}
//called like
myclass mc=make_class(&my_callback);

Don't for get to alter the constructor

template<typename CallBack>
myclass{
private:
   CallBack call_back;
public:
   myclass(CallBack call_back_)
   : call_back(call_back_)
   {}
};

or something like that

111111
  • 15,686
  • 6
  • 47
  • 62
  • Excellent, thanks for the info. I've adjusted MyClass as you suggested and I can now do: – David Williams Mar 02 '12 at 15:50
  • Meh, it seems I can't add more questions in the comments. Basically your solution does work for both functors and functions so thanks for that. There's a small syntactic issue I'm having with the functors, but I'll ask a new question if I can't work it out. – David Williams Mar 02 '12 at 15:52
  • @PolyVox Just edit your post or post it here ill try and help – 111111 Mar 02 '12 at 16:00
  • Thanks, but I worked it out. I was running into the 'most vexing parse' issue when trying to construct my functor. – David Williams Mar 02 '12 at 16:15
  • P.s. I can confirm that your solution is indeed faster than using std::function :-) – David Williams Mar 02 '12 at 16:16
  • of course it is, although there are many benefits to `std::function<>` too, the first of which is that you don't have to templatize your code so it can have a separate header and implementation and reduce code bloat. If the call back isn't frequently call `std::function` is often a better bet. – 111111 Mar 02 '12 at 16:17
  • Oh, sure, I think std::function is great for some cases. But my real code is already templatised anyway and the function is being called millions of times. It's actually a ray traversing a 3D grid and calling the callback for each element it touches. I do need to think about my users though... the std::function approach is simpler for them. I will think about it ;-) – David Williams Mar 02 '12 at 16:22
  • @PolyVox if you use the generate function I mentioned then actually it is not harder for your users at all. It might however increase compile times and code bloat. – 111111 Mar 02 '12 at 16:25
  • Actually I didn't test your make_class function, and I can't get it to work. Is the idea that it can create an instance of 'MyClass' without the user needing to know the type of their free function? So it should be used with free functions but not functors? Can you provide an example of how it is used? Also, should the first line actually include 'typename' and should the return type include ''? – David Williams Mar 02 '12 at 16:39
  • The idea is that it is able deduce the type of the parameter without having to be explicitly told. which is easier to use. It have added an example as to how that might be used. – 111111 Mar 02 '12 at 16:45
  • But in your line 'myclass mc=make_class(&my_callback);' surely you still need to place the type in angle brackets after 'myclass' as it is templatised. I.e. myclass mc = ..., in which case you still need to know the type? – David Williams Mar 02 '12 at 16:58
  • @PolyVox sorry I wasn't thinking, you are right, try `auto mc=myclass(&my_callback);` if you don't have C++11 this isn't going to work. – 111111 Mar 02 '12 at 17:10
  • No problem ;-) I can't use auto inside my library, but my users can and they are the ones who have to provide the callback. So I think I can use this. – David Williams Mar 02 '12 at 17:18
  • an obvious thing to do would be to create a typedef for the common usages, so somehthing like `typedef myclass mcvoid_t` or for quick usages to allow binding to anything you can reap some of the benefit of `std::function` by `typedef myclass mc_generic_t` which would bind to anything (inc functors, lanbda, std::bind) taking nothing and returning nothing – 111111 Mar 02 '12 at 17:22