C 函数回调与 C++ 方法回调

Callback from C function vs from C++ method

我有 Foo class 和 bar() 方法。 我还有一个 bar2() 函数(在任何 class 之外) 还有一个 Xpto class,我需要用一些回调来设置构造函数。

class Foo
{
  //...
  public:
     bar()
     {
       //do stuff..
     }
  //...
}

//isolated C function outside class
void bar2()
{
}

class Xpto
{
  //...
  public:
     Xpto(std::function<void()> &callback)
     {
       //do stuff..
     }
  //...
}

int main()
{
   Xpto x1(bar2); // <---- compiles

   Foo myFoo;
   Xpto x2(myFoo.bar); // <--- doesn't compile

   return 0;
}

为什么我可以使用 Foo 对象的回调方法创建 Xpto 对象?

因为 myFoo.bar 的签名不等于 std::function<void()>(因为它是成员函数)。您可以使用 std::bind(并查看使用成员函数指针的正确语法)。

Xpto x2(std::bind(&Foo::bar, std::ref(myFoo)));

您正在为 Xpto x1(bar2); 使用隐式转换。它调用 std::function<void()> 的隐式构造函数从 bar2.

创建一个

在第二种情况下,您提供的成员函数没有 void() 的签名。相反,如果是 void Foo:*()(指向成员函数的指针)。

要工作,您必须像这样使用 std::bind :

Xpto x2(std::bind(&Foo::bar, myFoo));

因为没有 ()s 的 myFoo.bar 实际上不是合法的 C++ 表达式(尽管这样的事情在 python 中是完全有意义的),而 bar2 只是一个指向返回 void 的 nullary 自由函数的指针,它可以转换为 std::function<void()>

引用成员函数的正确方法是 &Foo::bar,然后您还需要提供 Foo 的实例。您可以执行以下操作之一:

Xpto x2(std::bind(&Foo::bar, myFoo));
Xpto x2([myFoo]{ myFoo.bar(); });

另请注意,通常您不想std::function<Sig>之前接受争论。更喜欢将构造函数编写为:

template <typename F>
Xpto(F func) {
    // if you really need a std::function, create it here
}

如果你想使用方法,你应该为它使用一个签名,如:

class Xpto
{
  //...
  public:
     template <class T>
     Xpto(void (T::* func)())
     {
       //do stuff..
     }

     Xpto(std::function<void()> &callback)
     {
       //do stuff..
     }
  //...
}

这一行 void (T::* func)() 表示您将接受一个 return 无效的方法,并且不从对象 T 接收任何参数作为参数。

然后这样使用:

Xpto x2(&myFoo::bar);