3

在以下问题中,我遇到了与 Morpheus 提出的问题非常相似的问题:

重载的成员函数指针指向模板

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)foo(double)foo(double, double)都将分别与一个和两个模板参数的重载匹配connect(在双参数版本的情况下,将推导出第二个模板参数,第一个参数由您明确提供)。

如果您想消除模棱两可的情况,我建议您传递确切的类型,这样就不会发生意外。而不是那些重载,为什么不使用单个重载

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

原始代码的问题在于您明确定义了错误的部分。当您指定模板参数列表时,即使您指定了一个,编译器也会尝试推断出第二个,然后它会立即返回歧义,因为它不知道您是否要使用 (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 回答