10

イベントライブラリに取り組んでいますが、可変個引数テンプレートで問題が発生しています。

参照をパラメーターとして渡すことができないという事実を除いて、すべてが非常にうまく機能しています...

これは私の問題を明らかにするために書かれた非常に単純化された例です。

struct DelayedSignal 
{   
    ~DelayedSignal ()
    { std::cout << "~DelayedSignal CLOSE" << std::endl; }

    template<class C, class... Args>
    DelayedSignal ( void(C::*func)(Args...), C& obj )
    { std::cout << "DelayedSignal INIT - 03 - pointer to method & pointer to class instance (Arg num: " << sizeof...(Args) << ")" << std::endl; }

    template<class C, class... Args>
    DelayedSignal ( void(C::*func)(Args...), C& obj, Args... args )
    {
        std::cout << "DelayedSignal INIT - 04 - pointer to method & pointer to class instance & arguments (Arg num: " << sizeof...(Args) << ")" << std::endl;
    }
};

template<class... ArgsBis>
struct DelayedSignal_DebugHelper 
{
    ~DelayedSignal_DebugHelper ()
    { std::cout << "~DelayedSignal_DebugHelper CLOSE" << std::endl; }

    template<class C, class... Args>
    DelayedSignal_DebugHelper ( void(C::*func)(Args...), C& obj )
    { std::cout << "DelayedSignal_DebugHelper INIT - 03 - pointer to method & pointer to class instance (Arg num: " << sizeof...(Args) << ")" << std::endl; }

    template<class C, class... Args>
    DelayedSignal_DebugHelper ( void(C::*func)(Args...), C& obj, ArgsBis... args ) // Need to use ArgsBis instead of Args to make it work
    {
        std::cout << "DelayedSignal_DebugHelper INIT - 04 - pointer to method & pointer to class instance & arguments (Arg num: " << sizeof...(Args) << ")" << std::endl;
    }
};


template < class Tr, class... Args >
struct Signal
{
    void fire ( Args... args ) { std::cout << "Signal::fire::" << sizeof...(Args) << std::endl; }
};

struct Klass {};


int main()
{
    std::string str1("Blop");   // Will be used as reference
    Klass k;                    // Will be used as reference

    Signal<void, Klass&> signal_01;
    Signal<void, std::string&> signal_02;

    std::cout << "====== DelayedSignal :: needed for production purpose ===============" << std::endl;

    // OK
    DelayedSignal test01(&Signal<void, std::string&>::fire, signal_02);
    // HERE IS THE PROBLEM
    //DelayedSignal test02(&Signal<void, std::string&>::fire, signal_02, str1);

    // OK
    DelayedSignal test03(&Signal<void, Klass&>::fire, signal_01);
    // HERE IS THE PROBLEM
    //DelayedSignal test04(&Signal<void, Klass&>::fire, signal_01, k);

    std::cout << "====== DelayedSignal_DebugHelper :: used only for debug purpose ======" << std::endl;

    // OK
    DelayedSignal_DebugHelper<std::string&> test05(&Signal<void, std::string&>::fire, signal_02);
    // OK
    DelayedSignal_DebugHelper<std::string&> test06(&Signal<void, std::string&>::fire, signal_02, str1);

    // OK
    DelayedSignal_DebugHelper<Klass&> test07(&Signal<void, Klass&>::fire, signal_01);
    // OK
    DelayedSignal_DebugHelper<Klass&> test08(&Signal<void, Klass&>::fire, signal_01, k);

    return 1;
}

すべてのDelayedSignalインスタンスを単一のstd::listインスタンスに登録するときに、クラス自体でテンプレートを使用することを避けたいので、代わりにコンストラクターでテンプレートを使用します。すべてのDelayedSignalのベースとして純粋仮想クラスを使用し、仮想クラスへのポインターをstd :: listに登録することもできますが、仮想メソッドの使用を最小限に抑えるのが最善だと思います。この問題に本当に興味があります...

この例でわかるように、test02とtest04は、アクティブ化されるとエラーを返します。DelayedSignal_DebugHelperは、Argsテンプレート(メソッドテンプレート引数)の代わりに最後のコンストラクターでArgsBis(クラステンプレート引数)を使用するという事実を除いて、DelayedSignalとほぼ同じです。それ以外の場合は、(DelayedSignalのように)機能しません。Argsは受け入れられますが、同じコンストラクター宣言に含まれているという事実にもかかわらず、受け入れられvoid(C::*func)(Args...)ません。ArgsBis... args

私の知る限り、参照がない限り(DelayedSignal test04(&Signal<void, Klass>::fire, signal_01, k);たとえば)、または複数のパラメーターがない(またはない)限り、問題はありません。

この問題を解決する方法はありますか?

ありがとうございました。

4

3 に答える 3

2

私は絶対に素晴らしいエラーメッセージを出すclangを使用しています:

test.cpp:59:19: error: no matching constructor for initialization of 'DelayedSignal'
    DelayedSignal test02(&Signal<void, std::string&>::fire, signal_02, str1);
                  ^      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:9:5: note: candidate constructor template not viable: requires 2 arguments, but 3 were provided
    DelayedSignal ( void(C::*func)(Args...), C& obj )
    ^
test.cpp:13:5: note: candidate template ignored: deduced conflicting types for parameter 'Args'
      (<std::__1::basic_string<char> &> vs. <std::__1::basic_string<char>>)
    DelayedSignal ( void(C::*func)(Args...), C& obj, Args... args )
    ^

コンパイラは、次の競合する型を推測しますArgs

  1. std::string&
  2. std::string

これを修正する最善の方法は、まさにあなたがあなたのでそうした方法であると私は信じていますDelayedSignal_DebugHelper

于 2011-04-04T13:16:37.137 に答える
1

ハワード・ヒナントは正しいです...あなたが持っている他の可能性はどこでも参照を使用することです、例えば:

#include <iostream>

struct DelayedSignal 
{   
    ~DelayedSignal ()
     { std::cout << "~DelayedSignal CLOSE" << std::endl; }

    template<class C, class... Args>
    DelayedSignal ( void(C::*func)(Args &...), C& obj )
    { std::cout << "DelayedSignal INIT - 03 - pointer to method & pointer to class instance (Arg num: " << sizeof...(Args) << ")" << std::endl; }

    template<class C, class... Args>
    DelayedSignal ( void(C::*func)(Args &...), C& obj, Args & ... args )
    {
        std::cout << "DelayedSignal INIT - 04 - pointer to method & pointer to class instance & arguments (Arg num: " << sizeof...(Args) << ")" << std::endl;
    }
};

template < class Tr, class... Args >
struct Signal
{
     void fire ( Args &... args ) { std::cout << "Signal::fire::" << sizeof...(Args) << std::endl; }
};

struct Klass {};

int main()
{
    std::string str1("Blop");   // Will be used as reference
    Klass k;                    // Will be used as reference

    Signal<void, Klass&> signal_01;
    Signal<void, std::string&> signal_02;

    std::cout << "====== DelayedSignal :: needed for production purpose ===============" << std::endl;

    // OK
    DelayedSignal test01(&Signal<void, std::string&>::fire, signal_02);
    // HERE IS THE PROBLEM
    DelayedSignal test02(&Signal<void, std::string&>::fire, signal_02, str1);

}
于 2011-04-04T17:16:40.920 に答える
1

あなたが答えを受け入れたので、これは単なる補足です。見落としているかもしれませんがidentity、次のようなクラステンプレートを使用すると、コードをコンパイルできるようになります。
例えば:

template<class T> struct identity { typedef T type; };

struct DelayedSignal
{
    ...
    template<class C, class... Args>
    DelayedSignal ( void(C::*func)(Args...), C& obj, typename identity<Args>::type... args )
    {
       ...
    }
};

これがideoneのテストです

于 2011-04-05T20:10:12.297 に答える