Functions/functors as template parameters. Can they be stored?

12,402

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

Share:
12,402
David Williams
Author by

David Williams

Updated on July 04, 2022

Comments

  • David Williams
    David Williams almost 2 years

    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

  • David Williams
    David Williams over 12 years
    Excellent, thanks for the info. I've adjusted MyClass as you suggested and I can now do:
  • David Williams
    David Williams over 12 years
    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.
  • 111111
    111111 over 12 years
    @PolyVox Just edit your post or post it here ill try and help
  • David Williams
    David Williams over 12 years
    Thanks, but I worked it out. I was running into the 'most vexing parse' issue when trying to construct my functor.
  • David Williams
    David Williams over 12 years
    P.s. I can confirm that your solution is indeed faster than using std::function :-)
  • 111111
    111111 over 12 years
    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.
  • David Williams
    David Williams over 12 years
    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 ;-)
  • 111111
    111111 over 12 years
    @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.
  • David Williams
    David Williams over 12 years
    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 '<FuncType>'?
  • 111111
    111111 over 12 years
    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.
  • David Williams
    David Williams over 12 years
    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<type_here> mc = ..., in which case you still need to know the type?
  • 111111
    111111 over 12 years
    @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.
  • David Williams
    David Williams over 12 years
    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.
  • 111111
    111111 over 12 years
    an obvious thing to do would be to create a typedef for the common usages, so somehthing like typedef myclass<void(*)(void)> mcvoid_t or for quick usages to allow binding to anything you can reap some of the benefit of std::function by typedef myclass<std::function<void(void)> mc_generic_t which would bind to anything (inc functors, lanbda, std::bind) taking nothing and returning nothing