3

次の質問で、モーフィアスが提示した問題と非常によく似た問題があります。

テンプレートへのオーバーロードされたメンバ関数ポインタ

Richard Corden によって提案されたソリューションでは、オーバーロード間で区別するために、ユーザーが関数パラメーターの型を明示的に指定する必要があります。ただし、このソリューションは、同じ型のさまざまな数の引数を持つオーバーロードでは機能しないようです。

この例を考えてみましょう(元の質問から派生したもの):

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

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

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

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


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

GNU G++ 3.4.5 と MSVC 2008 は上記のコードをコンパイルせず、どちらも同様のエラー メッセージを表示します。

test.cpp: In function `int main()':
test.cpp:36: error: call of overloaded `connect(<unknown type>)' is ambiguous
test.cpp:7: note: candidates are: void A<T>::connect(void (T::*)(Arg1)) [with Arg1 = double, T = GApp]
test3.cpp:13: note:               void A<T>::connect(void (T::*)(Arg1, Arg2)) [with Arg1 = double, Arg2 = double, T = GApp]

ポインタをまったく同じ型の変数に代入するvoid (GApp::*tmp)(double) = &GApp::foo;connect((void (GApp::*)(double))(&GApp::foo));

ただし、私は最初の解決策を好み、それが機能しない理由を知りたいです。

前もって感謝します!

4

2 に答える 2

8

の場合a.connect<double> (&GApp::foo)、との両方が、それぞれ1つおよび2つのテンプレートパラメータのオーバーロードfoo(double)foo(double, double)一致しconnectます(2つのパラメータバージョンの場合、2番目のテンプレート引数が推定され、最初の引数は明示的に提供されます)。

あいまいなケースを明確にしたい場合は、正確なタイプを渡すことをお勧めします。そうすれば、予期せぬ事態が発生することはありません。それらの過負荷の代わりに、単一の過負荷を持ってみませんか

template<typename MType, typename T>
void connect(MType T::*f) 
{
  //Do some stuff
}

a.connect<void()> (&GApp::foo);
a.connect<void(double)> (&GApp::foo);
a.connect<void(double, double)> (&GApp::foo);

の最後の呼び出しconnectは、コードでも正常に機能するはずです。次に、個別のテンプレートを使用してタイプを分析しMTypeconnectパラメーターとリターンタイプを取得できます。

于 2011-03-31T23:13:54.703 に答える
0

元のコードの問題は、間違った部分を明示的に定義していることです。テンプレート パラメーターのリストを指定すると、1 つを指定した場合でも、コンパイラーは 2 番目のパラメーターを推測しようとしますが、(double,double) または (ダブル)バリエーション。

テンプレート パラメーターを定義する代わりに、コンパイラーにそれらを推測させますが、使用する foo() 関数のいずれかを明示的に指定します。

int main()
{
    A<GApp> a;
    a.connect (&GApp::foo);                                     // foo () - OK
    a.connect( ( void (GApp::*)(double) )&GApp::foo);           // foo (double) - OK
    a.connect( ( void (GApp::*)(double, double) ) &GApp::foo);  // foo (double,double) - OK
}
于 2011-04-01T07:57:09.103 に答える