2013-02-22 48 views
1

我試圖做一個模板類,它有一個Add方法,它將一個函數回調附加到類上,所以當我可以從那裏用指定的參數列表調用它時。它編譯得很好,除了部分在那裏我調用回調。它只是不接受參數,我嘗試了所有我能想到的,但它仍然給我相同的「無法擴展參數包」錯誤。我使用Visual Studio 2012微軟的Visual C++編譯器2012年11月CTP(v120_CTP_Nov2012) 下面是示例源: 模板 類可變參數 { 私人: 無效(*)($參數...)callbackPtr;向可變模板類添加回調 - 不可能?

public: 
    Variadic(); 
    ~Variadic(); 

    void Attach(void (*callback)($arguments...)); 

    void operator()($arguments... arguments); 
}; 

我再添加一個回調到它:

template<typename... $arguments> 
void Variadic<$arguments...>::Attach(void (*callback)($arguments...)) 
{ 
    callbackPtr = callback; 
} 

並與()操作我執行:

template<typename... $arguments> 
void Variadic<$arguments...>::operator()($arguments... arguments) 
{ 
    (callbackPtr)(arguments...); 
} 

在main.cpp中我做一個小試驗:

void test(int testInt, float testFloat) 
{ 
    //DoNothing 
} 

int main() 
{ 
Variadic<int, float> var; //create one that will have a callback that takes an int and a float argument 
var.Attach(test); //attach test, which takes an int and a float as arguments 
var(2, 3.0f); //try to call it 
} 

問題出現在我建立的時候 - 它給我2 e在這個確切的線上的錯誤:(callbackPtr)(arguments ...); 的錯誤是:

錯誤C3546: '...':有可擴展 錯誤C2065沒有參數包: '參數':未聲明的標識符

起初我還以爲這是一個語法問題,我沒有通過參數...正確,但我儘可能地嘗試,它仍然給我同樣的錯誤。我找不到有關「參數包擴展」谷歌或者。我可能做錯了什麼?我敢肯定, m以某種方式錯誤地使用(callbackPtr)(arguments ...);調用,但無法弄清楚如何。

任何幫助,將不勝感激。

+1

'無效(*)($參數...)callbackPtr;'難道不該'void(* callbackPtr)($ arguments ...);'? – jrok 2013-02-22 20:30:39

+0

嗯,如果我想添加多個在** std :: vector **中,如下所示:*** std :: vector 處理程序; *** for多個事件處理程序?不知道命名在這種情況下如何工作。 – 2013-02-22 20:38:22

+0

也許MSVS只是不接受'$'字符 – 2013-02-22 20:41:01

回答

1

在我進入了答案,有些事情你應該知道:

  • 微軟VC++ 2012年11月CTP沒有發揮好與Variadics和函數指針/函數簽名。在幾乎所有情況下,都需要手動擴展它們。它非常糟糕,但你必須忍受它,直到我們在VS和VC++上投入的所有資金實際上都取得成果,並且我們得到了一個具有其他編譯器已經支持的C++ 11功能的很好的編譯器。

  • 傳遞函數指針並讓編譯器確定正確的類型比大多數人在第一次臉紅時會有點棘手。有很多類型 誘惑 扣除和模板專業化進入它。

隨着的是,除了,它需要大量的模板魔術和很多有趣的功能,基於函數指針和成員函數有回調,而不是僅僅使用std::function<>。在我向您展示我最終使用的解決方案之前,我真誠地鼓勵您使用std::vector<std::function<[RETURNTYPE]([PARAMS])> >(或者僅爲std::function作爲單一回報),以免讓您嘗試完成所有工作的大量頭痛。無論如何,see my answer underneath @Insilico's for a Callback and Event system that works fine in GCC with variadic templates

對於在VC++中工作的版本,正如我之前所說的那樣,您必須手動破解各種定義,最終創建一個Callback Class和一個Event類。它是多個回調,但可以簡化Event類是單個連接/回調,如果你需要:

template<typename TFuncSignature> 
class Callback; 

///////////////// 
/* 2 ARGUMENT */ 
///////////////// 

template<typename R, typename T1, typename T2> 
class Callback<R (T1, T2)> { 
public: 
    typedef R (*TFunc)(void*, T1, T2); 

    const static size_t Arity = 2; 

    Callback() : obj(0), func(0) {} 
    Callback(void* o, TFunc f) : obj(o), func(f) {} 

    R operator()(T1 t1, T2 t2) const { 
     return (*func)(obj, t1, t2); 
    } 

    typedef void* Callback::*SafeBoolType; 
    operator SafeBoolType() const { 
     return func != 0? &Callback::obj : 0; 
    } 

    bool operator!() const { 
     return func == 0; 
    } 

    bool operator== (const Callback<R (T1, T2)>& right) const { 
     return obj == right.obj && func == right.func; 
    } 

    bool operator!= (const Callback<R (T1, T2)>& right) const { 
     return obj != right.obj || func != right.func; 
    } 

private: 
    void* obj; 
    TFunc func; 
}; 

namespace detail { 
    template<typename R, class T, typename T1, typename T2> 
    struct DeduceConstMemCallback2 { 
     template<R(T::*Func)(T1, T2) const> inline static Callback<R(T1, T2)> Bind(T* o) { 
      struct _ { static R wrapper(void* o, T1 t1, T2 t2) { return (static_cast<T*>(o)->*Func)(std::forward<T1>(t1, t2); } }; 
      return Callback<R(T1, T2)>(o, (R(*)(void*, T1, T2)) _::wrapper); 
     } 
    }; 

    template<typename R, class T, typename T1, typename T2> 
    struct DeduceMemCallback2 { 
     template<R(T::*Func)(T1, T2)> inline static Callback<R(T1, T2)> Bind(T* o) { 
      struct _ { static R wrapper(void* o, T1 t1, T2 t2) { return (static_cast<T*>(o)->*Func)(t1, t2)); } }; 
      return Callback<R(T1, T2)>(o, (R(*)(void*, T1, T2)) _::wrapper); 
     } 
    }; 

    template<typename R, typename T1, typename T2> 
    struct DeduceStaticCallback2 { 
     template<R(*Func)(T1, T2)> inline static Callback<R(T1, T2)> Bind() { 
      struct _ { static R wrapper(void*, T1 t1, T2 t2) { return (*Func)(t1), t2); } }; 
      return Callback<R(T1, T2)>(0, (R(*)(void*, T1, T2)) _::wrapper); 
     } 
    }; 
} 

template<typename R, class T, typename T1, typename T2> 
detail::DeduceConstMemCallback2<R, T, T1, T2> DeduceCallback2(R(T::*)(T1, T2) const) { 
    return detail::DeduceConstMemCallback2<R, T, T1, T2>(); 
} 

template<typename R, class T, typename T1, typename T2> 
detail::DeduceMemCallback2<R, T, T1, T2> DeduceCallback2(R(T::*)(T1, T2)) { 
    return detail::DeduceMemCallback2<R, T, T1, T2>(); 
} 

template<typename R, typename T1, typename T2> 
detail::DeduceStaticCallback2<R, T1, T2> DeduceCallback2(R(*)(T1, T2)) { 
    return detail::DeduceStaticCallback2<R, T1, T2>(); 
} 

template <typename T1, typename T2> class Event2 { 
public: 
    typedef void(* TSignature)(T1, T2); 
    typedef Callback<void(T1, T2)> TCallback; 
    typedef std::vector<TCallback> InvocationTable; 

protected: 
    InvocationTable invocations; 

public: 
    const static int ExpectedFunctorCount = 2; 

    Event2() : invocations() { 
     invocations.reserve(ExpectedFunctorCount); 
    } 

    Event2 (int expectedfunctorcount) : invocations() { 
     invocations.reserve(expectedfunctorcount); 
    } 

    template <void (* TFunc)(T1, T2)> void Add () { 
     TCallback c = DeduceCallback2(TFunc).template Bind<TFunc>(); 
     invocations.push_back(c); 
    } 

    template <typename T, void (T::* TFunc)(T1, T2)> void Add (T& object) { 
     Add<T, TFunc>(&object); 
    } 

    template <typename T, void (T::* TFunc)(T1, T2)> void Add (T* object) { 
     TCallback c = DeduceCallback2(TFunc).template Bind<TFunc>(object); 
     invocations.push_back(c); 
    } 

    template <typename T, void (T::* TFunc)(T1, T2) const> void Add (T& object) { 
     Add<T, TFunc>(&object); 
    } 

    template <typename T, void (T::* TFunc)(T1, T2) const> void Add (T* object) { 
     TCallback c = DeduceCallback2(TFunc).template Bind<TFunc>(object); 
     invocations.push_back(c); 
    } 

    void Invoke (T1 t1, T2 t2) { 
     size_t i; 
     for (i = 0; i < invocations.size(); ++i) { 
      invocations[i](t1, t2); 
     } 
    } 

    void operator() (T1 t1, T2 t2) { 
     size_t i; 
     for (i = 0; i < invocations.size(); ++i) { 
      invocations[i](t1, t2); 
     } 
    } 

    size_t InvocationCount () { 
     return invocations.size(); 
    } 

    template <void (* TFunc)(T1, T2)> bool Remove()   
    { return Remove (DeduceCallback2(TFunc).template Bind<TFunc>()); } 
    template <typename T, void (T::* TFunc)(T1, T2)> bool Remove (T& object) 
    { return Remove <T, TFunc>(&object); } 
    template <typename T, void (T::* TFunc)(T1, T2)> bool Remove (T* object) 
    { return Remove (DeduceCallback2(TFunc).template Bind<TFunc>(object)); } 
    template <typename T, void (T::* TFunc)(T1, T2) const> bool Remove (T& object) 
    { return Remove <T, TFunc>(&object); } 
    template <typename T, void (T::* TFunc)(T1, T2) const> bool Remove (T* object) 
    { return Remove (DeduceCallback2(TFunc).template Bind<TFunc>(object)); } 

protected: 

    bool Remove(TCallback const& target) { 
     auto it = std::find(invocations.begin(), invocations.end(), target); 
     if (it == invocations.end()) 
      return false; 
     invocations.erase(it); 
     return true; 
    } 

}; 
+0

哇,謝謝,有史以來最好的答案! – 2013-02-22 21:26:53

+0

隨時,我的好先生/小姐。 – 2013-02-22 21:31:42

+1

這是一個可怕的答案,你應該感覺很糟糕。 – 2013-02-22 21:32:31