T::* 在函数参数列表的声明中表示什么?

What does T::* signify in the declaration of a function parameter list?

我在我的代码中声明了一个特定的键盘回调函数:

void keyboardEventCallback(const pcl::visualization::KeyboardEvent &event, void* viewer_void, void* widget_void);

键盘事件是传递给回调函数的实际事件,viewer_void参数是指向生成window用于渲染的PCLVisualizerclass的指针,widget_void 是指向与 Qt 交互的小部件的指针。

在 pcl 的文档中,注册函数传递用于注册键盘函数的参数,如

boost::signals2::connection registerKeyboardCallback(void(T::*callback)(const pcl::visualization::KeyboardEvent&, void*), T& instance, void* cookie=nullptr)

所以我的问题是,注册函数声明中的T::*是什么意思为什么我不允许通过这个:

m_vis->registerKeyboardCallback(keyboardEventCallback, (void*)&m_vis, (void*)this);

其中 m_vis 是可视化工具,keyboardcallback 是回调,这是小部件。

为什么我这样注册不了。这是点云库。

这是成员函数的语法。

示例:

class A{
  int giveMe5();
};

&A::giveMe5;  // will be of type int(A::*)()

为什么类型不同于自由函数和静态成员函数? 因为成员函数有一个隐式参数指向函数被调用的对象。

https://isocpp.org/wiki/faq/pointers-to-members#fnptr-vs-memfnptr-types 说:

The type of this function is different depending on whether it is an ordinary function or a non-static member function of some class:

- Its type is int (*)(char,float) if an ordinary function

- Its type is int (Fred::*)(char,float) if a non-static member function of class Fred

what is the meaning of T::* inside the registration function declaration

这是成员指针的语法。我们看一下参数的整个类型和名称:

void(T::*callback)(const pcl::visualization::KeyboardEvent&, void*)

这是一个名为 callback 的变量的声明。它是一个 指向成员函数 的指针。更准确地说,它是指向 class T.

的成员函数的指针

如果我们把名称从类型中去掉,我们会看得更清楚:

// class name ---v     v------- parameters
            void(T::*)(const pcl::visualization::KeyboardEvent&, void*)
//          ^---- return type

它实际上是指向 class T 的函数成员的指针,即 returns void。这是一个 strictly 两个参数的函数:const pcl::visualization::KeyboardEvent&void*.

why am I not allowed to pass this

很简单。看你函数的类型:

using func_type = decltype(keyboardEventCallback);
// hint: the type is: void(*)(const pcl::visualization::KeyboardEvent&, void*, void*)

让我们并排比较这两种类型:

void(*)(const pcl::visualization::KeyboardEvent&, void*, void*)
void(T::*)(const pcl::visualization::KeyboardEvent&, void*)

首先,你的函数不是成员函数,它是一个普通的函数指针。这不是同一类型。然后,你得到了三个参数,因为参数的类型只要求两个。这是不同的。


现在,你怎么解决这个问题?

你可以使用 lambda:

auto myCallback = [](const pcl::visualization::KeyboardEvent& e, void* c) { /* ... */ }

using lambdaType = decltype(myCallback);

// Be careful here, we don't want our lambda to go out of scope when it is called.
m_vis->registerKeyboardCallback(&lambdaType::operator(), myCallback, this);

或者更简单:只需在 class 中定义 keyboardEventCallback,然后发送:

// don't forget: keyboardEventCallback must receive the same parameter as asked.
m_vis->registerKeyboardCallback(&MyClass::keyboardEventCallback, *this, this);