我正在尝试创建一个模板化的类,它有一个Add方法,将函数回调附加到该类,这样我就可以用指定的参数列表从那里调用它了。它编译得很好,除了我调用回调的部分。它只是不接受这些论点,我已经尝试了我能想到的一切,但它仍然给我同样的"无法扩展参数包"错误。我将Visual Studio 2012与Microsoft Visual C++编译器2012年11月版CTP(v120_CTP_Nov2012)一起使用以下是示例来源:样板变分类{私人:void(*)($arguments…)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
}
当我构建时,问题就来了——它在这一行给了我两个错误:(callbackPtr)(arguments…)错误为:
错误C3546:"…":没有可扩展的参数包错误C2065:"arguments":未声明的标识符
起初我认为这是一个语法问题,我没有传递参数没错,但我尽了一切可能,它仍然给了我同样的错误。我在谷歌上也找不到太多关于"参数包扩展"的信息。我可能做错了什么?我确信我在某种程度上错误地使用了(callbackPtr)(arguments…)调用,但不知道如何调用。
如有任何帮助,我们将不胜感激。
在我找到答案之前,你应该知道一些事情:
-
Microsoft VC++2012年11月的CTP在Variadics和函数指针/函数签名方面表现不佳。在几乎所有情况下,都需要手动展开它们。它非常糟糕,但你必须忍受它,直到我们在VS和VC++上投入的所有资金真正结出果实,我们得到了一个具有其他编译器已经支持的大量C++11功能的编译器。
-
传递函数指针和让编译器确定正确的类型比大多数人乍一看所猜测的要复杂一些。有很多类型
引诱扣除和模板专业化
除此之外,要基于函数指针和成员函数进行回调,而不仅仅是使用std::function<>
,还需要大量的模板魔法和大量有趣的功能。在我向您展示我最终使用的解决方案之前,我非常鼓励您使用std::vector<std::function<[RETURNTYPE]( [PARAMS] )> >
(或仅使用std::function
进行一次退货),以避免您在尝试解决这一切时遇到的巨大头痛。在任何一种情况下,请参阅@Insilico下面的我对回调和事件系统的回答,该系统在GCC中使用可变模板运行良好。
对于一个在VC++中工作的版本,正如我之前所说,你必须手动破解各种定义,我最终创建了一个回调类和一个事件类来完成。它用于多个回调,但如果需要,你可以将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;
}
};