6

次のようなテンプレートでメンバー関数ポインターを格納しようとしています:(これは私の実際のコードの簡略化されたバージョンです)

template<class Arg1>
void connect(void (T::*f)(Arg1)) 
{
    //Do some stuff
}

template<class Arg1>
void connect(void (T::*f)()) 
{
    //Do some stuff
}

class GApp
{
public:
    void foo() {}

    void foo(double d) {}
};

次に、GAppのすべてのオーバーロードされたメソッドに対して次のようにします。

connect(&GApp::foo); 

これを呼び出すことは問題ありませんfoo()が、どうすればこれを呼び出すことができfoo(double d)ますか?次が機能しないのはなぜですか?

connect((&GApp::foo)(double)); 

それは私に与えます

構文エラー:「double」の前に「)」を付ける必要があります

ここで使用する必要のある構文がわかりません。これはばかげた質問かもしれませんが、誰かがこれについて私を助けることができますか?

4

6 に答える 6

6

記述されたコードはコンパイルされません。私はあなたがやりたいことについていくつかの「仮定」をし、コードを変更しました。

要約すると、関数パラメーターのタイプを明示的に指定することにより、正しい関数を呼び出すことができます。

connect<double> (&GApp::foo);

connectメソッドがクラステンプレートのメンバーである場合、クラスタイプを指定する必要があるのは1回だけです。

template <typename T> class A
{
public:
  template<class Arg1>
  void connect(void (T::*f)(Arg1)) 
  {
    //Do some stuff
  }

  void connect(void (T::*f)()) 
  {
    //Do some stuff
  }
};

class GApp
{
public:
    void foo() {}
    void foo(double d) {}
};


int main ()
{
  A<GApp> a;
  a.connect (&GApp::foo);            // foo ()
  a.connect<double> (&GApp::foo);    // foo (double)
}

アップデート:

新しいコードサンプルに応じて、すべての情報が渡されます。「rare」の場合は「signal_void」の場合です。これは、シグナルにテンプレート引数がありますが、メンバー関数にはないためです。したがって、その例を特別な場合に使用して、完了です。以下がコンパイルされます。

template <class Arg = void>
class signal {};
signal<double> signal_double;
signal<> signal_void;

// Arg1 is deduced from signal<Arg1> and then we use it in the declaration
// of the pointer to member function
template<class T, class Arg1>
void connect ( signal<Arg1>& sig, T& obj, void (T::*f)(Arg1) ) {}

// Add special case for 'void' without any arguments
template<class T>
void connect (signal<> & sig, T& obj, void (T::*f)()) {}


void bar ()
{
  GApp myGApp;

  //Connecting foo()
  connect(signal_void, myGApp, &GApp::foo); // Matches second overload

  //Connecting foo(double)
  connect(signal_double, myGApp, &GApp::foo); // Matches first overload
}
于 2009-07-08T10:12:22.303 に答える
5

C ++プログラミング言語、3E、セクション7.7、p159:

関数へのポインタを割り当てるか初期化することにより、オーバーロードされた関数のアドレスを取得できます。その場合、ターゲットのタイプは、オーバーロードされた関数のセットから選択するために使用されます。例えば:

void f(int);
int f(char);

void (*pf1)(int) = &f;  // void f(int);
int (*pf2)(char) = &f;  // int f(char);
void (*pf3)(char) = &f; // error: no void f(char)

私の知る限り(まだチェックしていません)、同じことがメンバー関数にも当てはまります。したがって、解決策はおそらく2つの行に分割することです。

connect((&GApp::foo)(double));

になります:

void (GApp::*tmp)(double) = &GApp::foo;
connect(tmp);

変数を呼び出さないでくださいtmp;-)

まったく同じ理由で、newacctのキャストも安全だと思います。キャスト先void (GApp::*)(double)は、タイプの一時的なものを初期化することと同じであると定義されていますvoid (GApp::*)(double)。初期化に使用される式は&GApp::fooであるため、オーバーロードされた関数を使用した他の初期化に適用されるのと同じ魔法がキャストに適用されることを期待します。Stroustrupは、「関数へのポインター変数の初期化」とは言っておらず、「関数へのポインターの初期化」と言っています。したがって、一時的なものを含める必要があります。

したがって、ワンライナーを好む場合:

connect((void (GApp::*)(double))(&GApp::foo));

ただし、標準には私と同じ一貫性の考え方があると想定しており、チェックしていません。

于 2009-07-08T11:13:28.857 に答える
1

次のように、ポインタを明示的にキャストして、どのポインタを選択するかを知らせることができます。

connect((void (GApp::*)(double))&GApp::foo);

免責事項:それをテストしていません

于 2009-07-08T09:00:27.160 に答える
0

これは機能しています、

    typedef void (GApp::*MemberFunctionType)(double); 
    MemberFunctionType pointer = &GApp::foo;


  connect(MemberFunctionType);

何故ですか ?

編集

うーん..ええ。これは、newacctのソリューションと同じです。誰かが解決策を与えることができますか?

于 2009-07-08T09:06:32.780 に答える
0

boost::functionライブラリを使用しています...

#include <boost/function.hpp>

template<class Arg1>
void connect(boost::function1<void, Arg1*> fn) 
{
    //Do some stuff
}

template<class Arg1>
void connect(boost::function2<void, Arg1*, double> fn) 
{
    //Do some stuff
}

class GApp
{
public:
    void foo() {}

    void foo(double d) {}
};


int main()
{
    boost::function1<void,GApp*> f1 = (void (GApp::*)(void)) &GApp::foo;
    boost::function2<void,GApp*,double> f2 = (void (GApp::*)(double)) &GApp:foo;
    connect(f1);
    connect(f2);
    return 0;
}
于 2009-07-08T10:36:18.463 に答える
0

私の元のコードはこのようなものです、

コネクタ....

template<class T, class Arg1>
void connect(signal<Arg1>& sig,T& obj, void (T::*f)()) 
{
//  sig.insert(new GFunction<T, Arg1>(&obj,f));
}

template<class T, class Arg1
void connect(signal<Arg1>& sig,T& obj, void (T::*f)(Arg1)) 
{
//  sig.insert(new GFunction<T, Arg1>(&obj,f));
}

信号...

signal<double> signal_double;
signal<> signal_void;

応用...

class GApp
{
public:
    void foo() {}

    void foo(double d) {}
};

最後に、接続しています...

//Connecting foo()
        connect(signal_void, myGApp, &GApp::foo()); //Ok

//Connecting foo(double)
        connect(signal_double, myGApp, &GApp::foo()); // but ERROR!

シグナル用のテンプレートクラスがあります(ここでは言及されていません)。状況がより明確になったことを願っています。(またはそれはpreviousと同じですか?)。その2番目の接続は、foo()がない場合(foo(double)のみ)に機能します。それは私のコードが私を傷つけたものです。:(

于 2009-07-08T10:46:20.597 に答える