I declare a particular keyboard callback function as this inside my code:
void keyboardEventCallback(const pcl::visualization::KeyboardEvent &event, void* viewer_void, void* widget_void);
The keyboard event is the actual event passed to the callback function, the viewer_void parameter is a pointer to a PCLVisualizer class that generates a window for rendering, and widget_void is a pointer to a widget that interfaces with Qt.
In the documentation for pcl, a registration function passes the arguments for registering the keyboard function like
boost::signals2::connection registerKeyboardCallback(void(T::*callback)(const pcl::visualization::KeyboardEvent&, void*), T& instance, void* cookie=nullptr)
So my question is, what is the meaning of T::*
inside the registration function declaration, and why am I not allowed to pass this:
m_vis->registerKeyboardCallback(keyboardEventCallback, (void*)&m_vis, (void*)this);
where m_vis
is a visualizer, keyboardcallback
is the callback, and this is the widget.
Why can I not register like this. This is for the point cloud library.
The function declarator includes the list of parameters that can be passed to the function when it is called by another function, or by itself. In C++, the parameter list of a function is referred to as its signature. The name and signature of a function uniquely identify it.
The parameter list of a function describes the number and types of the arguments that the function accepts, and the number and types of the values it returns. The parameter list of a generic function is used to define the overall protocol of the generic function.
It means a reference to a pointer to an int. In other words, the function can change the parameter to point to something else. To pass a variable in, just pass an int*. As awoodland points out, what's passed in must be an l-value.
The parameter list refers to the type, order, and number of the parameters of a function. Parameters are optional; that is, a function may contain no parameters. Function Body − The function body contains a collection of statements that define what the function does.
what is the meaning of T::* inside the registration function declaration
This is the syntax of a pointer to member. Let's take a look at the whole type and name of the parameter:
void(T::*callback)(const pcl::visualization::KeyboardEvent&, void*)
This is the declaration of a variable named callback
. It's a pointer to member function. More precisely, it's a pointer to member function of the class T
.
If we take the name out of the type, we see things more clearly:
// class name ---v v------- parameters
void(T::*)(const pcl::visualization::KeyboardEvent&, void*)
// ^---- return type
It's in fact, a pointer to function member of the class T
that returns void
. It's a function that takes strictly two parameters: a const pcl::visualization::KeyboardEvent&
and a void*
.
why am I not allowed to pass this
It's simple. Look at the type of your function:
using func_type = decltype(keyboardEventCallback);
// hint: the type is: void(*)(const pcl::visualization::KeyboardEvent&, void*, void*)
Let's compare the two types side by side:
void(*)(const pcl::visualization::KeyboardEvent&, void*, void*)
void(T::*)(const pcl::visualization::KeyboardEvent&, void*)
First, your function is not a member function, it's a plain function pointer. It's not the same type. Then, you got three arguments, as the type of the parameter only ask for two. This is different.
Now, how can you fix this??
You could use a 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);
Or even simpler: just define keyboardEventCallback
inside your class, and send it:
// don't forget: keyboardEventCallback must receive the same parameter as asked.
m_vis->registerKeyboardCallback(&MyClass::keyboardEventCallback, *this, this);
This is the syntax for member functions.
Example:
class A{
int giveMe5();
};
&A::giveMe5; // will be of type int(A::*)()
Why does the type differ from free functions and static member functions ? Because member functions have an implicit parameter that points to the object on which the function gets called.
https://isocpp.org/wiki/faq/pointers-to-members#fnptr-vs-memfnptr-types says:
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 isint (*)(char,float)
if an ordinary function
- Its type isint (Fred::*)(char,float)
if a non-static member function of class Fred
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With