向可变模板类添加回调 - 不可能? [英] Adding a callback to a variadic template class - impossible?

查看:264
本文介绍了向可变模板类添加回调 - 不可能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个模板类,它有一个Add方法,附加一个函数回调到类,所以当我可以从那里调用指定的参数list.It编译很好,除了部分,其中我调用回调。它只是不接受参数,我试过了我可以想到的一切,但它仍然给我相同的不能扩展参数包error.Im使用 Visual Studio 2012 Microsoft Visual C ++编译器2012年11月CTP(v120_CTP_Nov2012)
下面是示例源代码:
template
class Variadic
{
private:
void(*)($ arguments ...)callbackPtr;

  public:
Variadic();
〜Variadic();

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

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

然后我添加回调:

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

使用()操作符执行:

 模板< 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; //创建一个将有一个回调函数接受一个int和一个float参数
var.Attach(test); // attach test,它接受一个int和一个float作为参数
var(2,3.0f); //尝试调用它
}

问题出现在我构建时 - 在此确切行中出现2个错误: (callbackPtr)(arguments ...);
错误是:




错误C3546:'...':没有可扩展的参数包
错误C2065:'arguments':undeclared identifier


起初我以为这是一个语法问题,我没有正确传递参数... ,但我尽了一切可能,仍然给我相同的错误。我无法找到很多信息参数包扩展在google中。我可以做错了什么我确定我不知何故不正确地使用 (callbackPtr)(arguments ...); 调用,但不知道如何。



解决方案

在我得到答案之前,你应该知道一些事情:




  • Microsoft VC ++ 2012年11月CTP不适用于Variadics和函数指针/函数签名。在几乎所有情况下,都需要手动将其展开。它主要是吸引,但你必须忍受它,直到所有我们抛在VS和VC ++的钱实际上带来了果实,我们得到一个编译器有一个很好的C ++ 11功能,其他编译器已经支持。 p>


  • 传递函数指针并使编译器确定正确的类型比大多数人在初次腮红时猜测的要复杂一些。




有了除此之外,它需要大量的模板魔法和很多有趣的功能,基于函数指针和成员函数的回调,而不是只使用 std :: function<> 。在我告诉你我最终使用的解决方案之前,我真诚地鼓励你使用 std :: vector< std :: function< [RETURNTYPE]([PARAMS])> > (或只是 std :: function 用于单个返回),以保存自己,试图使这一切都工作出来的大量头痛。无论在哪种情况下,请参阅@ Insilico's下的我的回答,以了解在GCC中使用可变参数模板正常工作的回调和事件系统。



对于一个在VC ++中工作的版本,如前所述,你必须手工去掉各种定义,我最后创建一个回调类和一个Event类去做。它用于多个回调,但如果您需要,可以将 Event 类简化为单个附加/回调:

 模板< 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){}
回调(void * o,TFunc f):obj
$ b R运算符()(T1 t1,T2 t2)const {
return(* func)(obj,t1,t2);
}

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

bool操作符! ()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>内联静态回调< R(T1,T2)> Bind(T * o){
struct _ {static R wrapper(void * o,T1 t1,T2 t2){return(static_cast< T * (void *,T1,T2))_ :: wrapper()返回的返回(T1,T2,T1,T2,T1,T2) ;
}
};

template< typename R,class T,typename T1,typename T2>
struct DeduceMemCallback2 {
template& :: * Func)(T1,T2)>内联静态回调< R(T1,T2)> Bind(T * o){
struct _ t2){return(static_cast< T *(o)→Func)(t1,t2)); }};
return Callback< R(T1,T2)>(o,(R(*)(void *,T1,T2))_
}
};

template< typename R,typename T1,typename T2>
struct DeduceStaticCallback2 {
template< R(* Func)(T1,T2)>内联静态回调< 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))_
}
};
}

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回调< void(T1,T2)> TCallback;
typedef std :: vector< TCallback>调用表;

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 [i](t1,t2);
}
}

void operator()(T1 t1,T2 t2){
size_t i;
for(i = 0; 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删除(TCallback const& target){
auto it = std :: find(invocations.begin(),invocations.end ),target);
if(it == invocations.end())
return false;
invocations.erase(it);
return true;
}

};


I'm trying to make a templated class, which has an Add method, that attaches a function callback to the class, so when I can then call it from there with the specified arguments list.It compiles fine, except for the part where I invoke the callback.It just doesn't accept the arguments, I've tried everything I can think of, but it still gives me the same "cannot expand parameter pack" error.Im using Visual Studio 2012 with the Microsoft Visual C++ Compiler Nov 2012 CTP (v120_CTP_Nov2012) Here is the example source: template class Variadic { private: void (*)($arguments...) callbackPtr;

public:
    Variadic();
    ~Variadic();

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

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

I then add a callback to it:

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

And with the () operator I execute it:

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

In main.cpp I do a small test:

    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
}

The problem comes when I build - it gives me 2 errors at this exact line: (callbackPtr)(arguments...); The errors are:

error C3546: '...' : there are no parameter packs available to expand error C2065: 'arguments' : undeclared identifier

At first I thought it was a syntax problem and I wasn't passing arguments... properly, but I tried every way possible, it still gives me the same error.I can't find much info on "parameter pack expansion" in google either.What could I be doing wrong?I'm sure I'm somehow incorrectly using the (callbackPtr)(arguments...); call, but can't figure out how.

Any help would be appreciated.

解决方案

Before I get into the answer, some things you should know:

  • The Microsoft VC++ November 2012 CTP does not play nice with Variadics and Function Pointers / Function Signatures. In almost all cases, it is necessary to expand them manually by hand. It sucks majorly, but you'll have to live with it until all that money we throw at VS and VC++ actually bears fruit and we get a compiler with a good chunk of C++11 features that other compilers are already supporting.

  • Passing function pointers and having the compiler determine the right type is a little trickier than most people would guess at first blush. There's a lot of type seducing deducting and template specialization that goes into it.

With that aside, it takes a lot of template magic and a lot of interesting functionality to have callbacks based on function pointers and member functions, rather than just using std::function<>. Before I show you the solution I ended up using, I seriously encourage you to use a std::vector<std::function<[RETURNTYPE]( [PARAMS] )> > (or just std::function for a single return) to save yourself the massive headache of trying to make this all work out. In either case, see my answer underneath @Insilico's for a Callback and Event system that works fine in GCC with variadic templates.

For a version that works in VC++, as I said before, you have to hack away at the various definitions manually, which I ended up creating a Callback Class and an Event class to do. It's for multiple callbacks, but you can simplify the Event class to be a single attach/callback if you need to:

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;
    }

};

这篇关于向可变模板类添加回调 - 不可能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆