Search code examples
c++qtcallbackvoidpoint-cloud-library

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


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.


Solution

  • 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);