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

Mor*_*eus 6 c++ templates pointer-to-member

我试图通过这样的模板存储成员函数指针:(这是我的真实代码的简化版本)

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) {}
};
Run Code Online (Sandbox Code Playgroud)

然后我想对GApp中的每个重载方法执行以下操作:

connect(&GApp::foo); 
Run Code Online (Sandbox Code Playgroud)

打电话给这个foo()是好的,但我怎么称它为foo(double d)?以下为什么不工作?

connect((&GApp::foo)(double)); 
Run Code Online (Sandbox Code Playgroud)

它会给我

语法错误:'double'应以')'开头

我不明白这里必须使用的语法.这可能是一个愚蠢的问题,但任何人都可以帮助我吗?

Ric*_*den 6

您编写的代码无法编译.我对你想做的事做了一些"假设",并改变了代码.

总而言之,您可以通过显式指定函数参数类型来调用正确的函数:

connect<double> (&GApp::foo);
Run Code Online (Sandbox Code Playgroud)

如果connect方法是类模板的成员,那么只需要指定一次类类型:

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)
}
Run Code Online (Sandbox Code Playgroud)

更新:

为了响应新的代码示例,所有信息都被传入."罕见"情况是'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
}
Run Code Online (Sandbox Code Playgroud)


Ste*_*sop 5

C++编程语言,3E,第7.7节,第159页:

您可以通过分配或初始化函数指针来获取重载函数的地址.在这种情况下,目标的类型用于从重载函数集中进行选择.例如:

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)
Run Code Online (Sandbox Code Playgroud)

据我所知(尚未检查),这同样适用于成员函数.所以解决方案可能分为两行:

connect((&GApp::foo)(double));
Run Code Online (Sandbox Code Playgroud)

变为:

void (GApp::*tmp)(double) = &GApp::foo;
connect(tmp);
Run Code Online (Sandbox Code Playgroud)

永远不要调用变量tmp;-)

我猜想newacct的演员也是安全的,原因完全相同.转换void (GApp::*)(double)为定义与初始化临时类型相同void (GApp::*)(double).由于用于初始化它的表达式是&GApp::foo,我希望应用于强制转换的相同魔术应用于具有重载函数的任何其他初始化.Stroustrup没有说"初始化一个指向函数的指针变量",他说"初始化一个指向函数的指针".所以这应该包括临时工.

所以如果你喜欢单行:

connect((void (GApp::*)(double))(&GApp::foo));
Run Code Online (Sandbox Code Playgroud)

但是,我假设标准与我一致的想法一致,我没有检查.