2013-02-22 3 views
1

Я пытаюсь создать шаблонный класс, который имеет метод Add, который присоединяет функцию callback к классу, поэтому, когда я могу затем вызвать ее там с указанными аргументами list.It компилируется отлично, за исключением части где я вызываю callback.It просто не принимает аргументы, я пробовал все, что я могу думать, но он по-прежнему дает мне то же самое "не может расширять пакет параметров" error.Im с использованием Visual Studio 2012 с Microsoft Visual C++ Compiler ноябрь 2012 CTP (v120_CTP_Nov2012) Вот пример источник: шаблона класса VARIADIC { частного: недействительных (*) ($ аргументы ...) 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 rrors на этой точной строке: (callbackPtr) (аргументы ...); Ошибки: C3546

ошибка: '...': нет пакетов параметров, доступных для расширения ошибки C2065: 'аргументы': необъявленный идентификатор

Сначала я подумал, это была синтаксическая проблема, и я не пропустил аргументов ... правильно, но я старался изо всех сил, это все равно дает мне ту же ошибку. Я не могу найти много информации об «расширение пакета параметров» в google. Что я могу делать неправильно? Я уверен, что я ' m как-то неправильно использовать (callbackPtr) (аргументы ...); звонок, но не можете понять как.

Любая помощь будет оценена по достоинству.

+1

'недействительным (*) ($ аргументы ...) callbackPtr;' Если это не будет 'void (* callbackPtr) ($ arguments ...);'? – jrok

+0

Хмм, что, если я хочу добавить несколько в ** std :: vector ** вот так: *** std :: vector обработчики; *** для несколько обработчиков событий? Не знаете, как именование будет работать в этом случае. –

+0

Может быть, MSVS просто не принимает символ '$' –

ответ

1

Перед тем, как попасть в ответ, некоторые вещи, которые вы должны знать:

  • для Microsoft VC++ ноября 2012 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 и класс 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

wow, спасибо, лучший ответ когда-либо! –

+0

В любое время, мой хороший сэр/мадам. – 2013-02-22 21:31:42

+1

Это ужасный ответ, и вы должны чувствовать себя ужасно. –

Смежные вопросы