2017-05-20 186 views
1

我有以下委託類:事件委託在C++中

template <typename RetVal, typename ...Args> 
    class KxCEventDelegate 
    { 
     union InstancePtr 
     { 
      InstancePtr(void) : as_void(nullptr) {} 

      void* as_void; 
      const void* as_const_void; 
     }; 

     typedef RetVal(*InternalFunction)(InstancePtr, Args&& ...args); 
     typedef std::pair<InstancePtr, InternalFunction> Stub; 

     // Turns a free function into internal function stub 
     template <RetVal(*Function)(Args ...args)> 
     static KX_INLINE RetVal FunctionStub(InstancePtr, Args&& ...args) 
     { 
      // we don't need the instance pointer because we're dealing with free functions 
      return (Function)(std::forward<Args>(args)...); 
     } 

     // Turns a member function into internal function stub 
     template <class C, RetVal (C::*Function)(Args ...args)> 
     static KX_INLINE RetVal ClassMethodStub(InstancePtr instance, Args&& ...args) 
     { 
      // cast the instance pointer back into the original class instance 
      return (static_cast<C*>(instance.as_void)->*Function)(std::forward<Args>(args)...); 
     } 

     // Turns a member function into internal function stub 
     template <class C, RetVal(C::*Function)(Args ...args) const> 
     static KX_INLINE RetVal ClassMethodStubConst(InstancePtr instance, Args&& ...args) 
     { 
      // cast the instance pointer back into the original class instance 
      return (static_cast<const C*>(instance.as_const_void)->*Function)(std::forward<Args>(args)...); 
     } 

    public: 
     // Binds a free function 
     template <RetVal(*Function)(Args ...args)> 
     void Bind(void) 
     { 
      m_stub.first.as_void = nullptr; 
      m_stub.second = &FunctionStub<Function>; 
     } 

     // Binds a class method 
     template <class C, RetVal (C::*Function)(Args ...args)> 
     void Bind(C* instance) 
     { 
      m_stub.first.as_void = instance; 
      m_stub.second = &ClassMethodStub<C, Function>; 
     } 

     // Binds a class method 
     template <class C, RetVal(C::*Function)(Args ...args) const> 
     void BindConst(const C* instance) 
     { 
      m_stub.first.as_const_void = instance; 
      m_stub.second = &ClassMethodStubConst<C, Function>; 
     } 

     // Invokes the delegate 
     RetVal Invoke(Args ...args) const 
     { 
      KX_ASSERT(m_stub.second != nullptr, "Cannot invoke unbound delegate. Call Bind() first.", m_stub.second, nullptr); 
      return m_stub.second(m_stub.first, std::forward<Args>(args)...); 
     } 

    private: 
     Stub m_stub; 
    }; 

用法是這樣的(自由功能):

int FreeFunctionInt(int i) 
    { 
     return i; 
    } 

    KxCEventDelegate<int, int> delegate; 
    delegate.Bind<&FreeFunctionInt>(); 
    int ret = delegate.Invoke(10); 

現在,我想實現一個通用GetEventDelegate功能,類似到C#。這是我帶來的:

// Gets event delegate. 
    template <typename RetVal, typename ...Args> 
    KxCEventDelegate<RetVal, Args...> GetEventDelegate(RetVal(*Function)(Args ...args)) 
    { 
     KxCEventDelegate<RetVal, Args...> delegate; 
     delegate.Bind<Function>(); 
     return delegate; 
    } 

這是我無法弄清楚什麼是錯的部分。這似乎是delegate.Bind<Function>();的問題。編譯器給了我以下錯誤:

1>------ Build started: Project: Tests, Configuration: Debug x64 ------ 
1>Main.cpp 
1>c:\sdk\kx\kxengine\include\events\delegate.h(88): error C2672: 'kx::events::KxCEventDelegate<int,int>::Bind': no matching overloaded function found 
1>c:\sdk\kx\tests\eventstests.h(76): note: see reference to function template instantiation 'kx::events::KxCEventDelegate<int,int> kx::events::GetEventDelegate<int,int>(RetVal (__cdecl *)(int))' being compiled 
1>  with 
1>  [ 
1>   RetVal=int 
1>  ] 
1>c:\sdk\kx\kxengine\include\events\delegate.h(88): error C2974: 'kx::events::KxCEventDelegate<int,int>::Bind': invalid template argument for 'C', type expected 
1>c:\sdk\kx\kxengine\include\events\delegate.h(58): note: see declaration of 'kx::events::KxCEventDelegate<int,int>::Bind' 
1>c:\sdk\kx\kxengine\include\events\delegate.h(88): error C2975: 'Function': invalid template argument for 'kx::events::KxCEventDelegate<int,int>::Bind', expected compile-time constant expression 
1>c:\sdk\kx\kxengine\include\events\delegate.h(49): note: see declaration of 'Function' 
1>Done building project "Tests.vcxproj" -- FAILED. 
+2

[如何創建最小,完整和可驗證示例](https://stackoverflow.com/help/mcve) – Pavel

回答

2

在這個片段中,你一般GetEventDelegate功能:

template <typename RetVal, typename ...Args> 
KxCEventDelegate<RetVal, Args...> GetEventDelegate(RetVal(*Function)(Args ...args)) { 
    KxCEventDelegate<RetVal, Args...> delegate; 
    delegate.Bind<Function>(); 
    return delegate; 
} 

Function不是一個常量表達式,因爲它應該是,如果你打算使用它作爲一個模板參數。
在C++ 11/14中,你可以用另一個間接級別來解決它。事情是這樣的:

template <typename RetVal, typename ...Args> 
struct Factory { 
    template<RetVal(*Function)(Args...)> 
    static KxCEventDelegate<RetVal, Args...> GetEventDelegate() { 
     KxCEventDelegate<RetVal, Args...> delegate; 
     delegate.Bind<Function>(); 
     return delegate; 
    } 
}; 

,你可以,因爲它遵循使用方法:

auto delegate = Factory<int, int>::GetEventDelegate<&FreeFunctionInt>(); 

無論如何,我會建議一個靜態函數添加到委託類,而不是用它作爲直接嵌入一個工廠方法在類型本身。
東西你最終會爲調用:

auto delegate = KxCEventDelegate<int, int>::create<&FreeFunctionInt>(); 

它更容易爲讀者瞭解發生了什麼,從我的角度來看怎麼回事引擎蓋下,至少。