1

クラスに関数コールバックをアタッチするAddメソッドを持つテンプレート化されたクラスを作成しようとしています。そのため、指定された引数リストを使用してそこから呼び出すことができます。コールバックを呼び出します。引数を受け入れないだけです。考えられることはすべて試しましたが、それでも同じ「パラメーター パックを展開できません」というエラーが表示されます。Microsoft Visual C++ コンパイラでVisual Studio 2012を使用しています。 2012 CTP (v120_CTP_Nov2012) サンプル ソースは次のとおりです。

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つのエラーが発生します: (callbackPtr)(arguments...); エラーは次のとおりです。

エラー C3546: '...': 展開に使用できるパラメーター パックがありませんエラー C2065: '引数': 宣言されていない識別子

最初は構文の問題だと思い、引数を適切に渡していませんでしたが、可能な限りあらゆる方法を試しましたが、それでも同じエラーが発生します。「パラメーターパック展開」に関する情報はあまり見つかりませんgoogle どちらか.何が間違っているのでしょうか? (callbackPtr)(arguments...);を何らかの形で間違って使用していると確信しています。呼び出しますが、方法がわかりません。

どんな助けでも大歓迎です。

4

1 に答える 1

1

答えに入る前に、知っておくべきことがいくつかあります。

  • Microsoft VC++ 2012 年 11 月の CTP は、Variadics および関数ポインター/関数シグネチャーとうまく機能しません。ほとんどの場合、手動で展開する必要があります。たいへんひどいものですが、VS と VC++ に投じたすべての資金が実際に実を結び、他のコンパイラが既にサポートしている C++11 機能のかなりの部分を備えたコンパイラを手に入れるまで、あなたはそれと一緒に暮らす必要があります。

  • 関数ポインターを渡し、コンパイラーに適切な型を判断させることは、ほとんどの人が一見して推測するよりも少しトリッキーです。そこには、型を誘惑する推論とテンプレートの特殊化がたくさんあります。

それはさておき、単にstd::function<>. 私が最終的に使用したソリューションを紹介する前に、これをすべてうまく機能させようとする大きな頭痛の種を避けるために、 a std::vector<std::function<[RETURNTYPE]( [PARAMS] )> >(または1 回のリターンのみ)を使用することを真剣にお勧めします。std::functionいずれの場合も、@Insilico の下にある私の回答を参照してください。コールバックおよびイベント システムは、GCC で 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;
    }

};
于 2013-02-22T21:02:20.940 に答える