C++ passing method pointer as template argument

前端 未结 5 943
攒了一身酷
攒了一身酷 2021-01-19 23:44

I have a caller function like this:

template
void CallMethod(T *object){
    (object->*method)(args);
}


        
相关标签:
5条回答
  • 2021-01-20 00:24

    What if 2 methods have the exact same signature ?

    The template can not distinguish on it (it selects on type, not value) and thus the same generated template function will call the first method or the second, would you bet your hand on it ?

    You can use some tricks to make a different type at compile time, using the __LINE__ macro, but it involves mixing macro with current code which will be hard to follow. This code:

    template<typename T, void (T::*method)(), int>
    void CallMethod(T *) { ... }
    #define MakeCallMethod(X, Y) &CallMethod<X, X::&Y, __LINE__>
    
    // This will work (it does not without the __LINE__ trick, ptr1 == ptr2 in that case)
    typedef void (*ptrFunc)(A *);
    ptrFunc ptr1 = MakeCallMethod(A, method);
    ptrFunc ptr2 = MakeCallMethod(A, otherMethodWithSameSignature);
    
    Assert(ptr1 != ptr2);
    

    However you'll not be able to save the pointer to a method in a variable and make a "auto wrapper" from it. It's now runtime, you need a runtime solution for this.

    0 讨论(0)
  • 2021-01-20 00:38

    At this point I have ascertained that you have an API that takes a function and a pointer and you need to supply it such. I assume that you must always supply it an A* pointer?

    If it is a very generic callback but must be a function (can't be a boost::function) and must be a pointer (possibly void*) then you need a function a bit like this:

    struct GenericHolder
    {
       boost::function0<void> func;
    };
    
    void GenericCallback( void * p )
    {
       GenericHolder * holder = static_cast< GenericHolder * >(p);
       holder->func();
       delete holder;
    }
    

    As in this case I am calling delete at call time, so I have assume we call new at invoke time, i.e. when you build up your pointer on which your call is made. Of course it might not be that your pointer you pass is deleted on first call, so manage the lifetime appropriately.

    If you are in control of the "other side" then don't do this by design but let that side hold the boost::function and just call it.

    Memory management can still be an issue you need to take care of. For example, when you call boost::bind it wraps things in a struct behind the scenes for you. If these are pointers you allocated with new you need to delete them at sometime. If they are references they must still be valid at the point of call. pointers to local variables can also be a problem. shared_ptrs are ideal, of course. And the bug tracking to the boost::bind error is very very hard to find if you use that concept a lot.

    0 讨论(0)
  • 2021-01-20 00:42

    It looks like you're trying to implement an interface via templates. It might be possible, but wouldn't it be nicer to have a base class with a virtual function, and use a base class pointer to access the virtual function via a simple function call?

    Header:

    class AbstractBase
    {
    public:
        virtual void func() = 0;
    }
    class SubClass : public AbstractBase
    {
    public:
        void func();
    }
    

    Source file:

    void SubClass::func()
    {
        std::cout << "Virtual function called.\n";
    }
    

    Example usage:

    int main()
    {
        AbstractBase* base;
        base = new SubClass();
        base->func(); // virtual function call through base pointer will use SubClass's implementation
        return 0;
    }
    

    You can store a vector of pointers (or smart pointers if you use boost or C++0x) which you can loop through and use this to do all kinds of SubClass dependent stuff.

    Alternatively, use boost::function or std::function (C++0x) which is an object containing the member function in question and pass that as a template parameter, using the object instance as a first argument. Which comes down to a workaround of the above.

    UPDATE: Seeing that you need a plain C function pointer, there are some tricks that might imapct runtime performance in c++0x or boost: bind, function::target and so forth...

    You will need this to get a function pointer out of a std/boost::function, and this to bind the first argument to an object. bind acts at runtime, so maybe a template would be better in this case...

    0 讨论(0)
  • 2021-01-20 00:42

    First, please create typedefs http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.5

    Second,

    void (*function)(A *) = &CallMethod<A, method>;
    

    In this case, method is a variable and variables can not be template arguments. I haven't tested it but perhaps you could try...

    void (*function)(A *) = &CallMethod<A, void (A::*method)()>;
    
    0 讨论(0)
  • 2021-01-20 00:44

    All template parameters must be known at compile time. So if method is really a variable and not a particular function, there is no way to do what you want.

    Instead, you may be able to make a template struct which has a pointer to member function as a member and implements an operator() which acts similarly to CallMethod<A, method>.

    0 讨论(0)
提交回复
热议问题