c++function-pointerspointer-to-member

How to use a pointer to a member function as a field of a struct data member to call a member function?


I am trying to port C code to a C++ program and thus encapsulate the logic from the C program inside a C++ class. The step I am stuck at is using a function pointer, which is a field inside a struct data member, to call a member function.

I tried to extract only the involved code from the header, source, and driver files:

The C++ header looks as follows :

#include <array>

#include <cstdint>

class MY_CLASS {
public :
    // 1. within-class definition of the function pointer type :
    typedef uint8_t * ( MY_CLASS :: * func_ptr_type ) ( uint8_t in_uint8 ) ;
    
    // 2. within-class definition of the struct type :
    typedef struct _struct_with_func_ptr {
        func_ptr_type func_ptr_member ;
    } struct_with_func_ptr_type ;
    
    // 3. declaration of a data member of the struct type :
    struct_with_func_ptr_type struct_with_func_ptr_data_member ;
    
    // 4. declaration of the member function to be assigned to the function pointer of the struct data member :
    uint8_t * func_to_be_assigned_to_func_ptr ( uint8_t in_uint8 ) ;
    
    // 5. array as data member to be accessed by the member function, assigned to the function pointer of the struct data member :
    std :: array < uint8_t, 5 > array_data_member ;
    
    // 6. declaration of the member function to make use of the function pointer of the struct data member :
    void func_to_make_use_of_func_ptr ( uint8_t in_uint8 ) ;
    
    // 7. Constructor declaration :
    MY_CLASS () ;

} ;

extern MY_CLASS my_object ;

Originally in the C program the definition of the function pointer looked so: typedef uint8_t * ( * func_ptr_type ) ( uint8_t in_uint8 ) ; but as long as I understood from online links, I need a pointer to a member function rather than a regular C function pointer, e.g. https://web.archive.org/web/20120723071248/http://www.dulcineatech.com/tips/code/c++/member-pointers.html

My C++ source looks as follows :

#include <iostream>

#include "my_header.hpp"

MY_CLASS :: MY_CLASS () :
    array_data_member {}
{} ;

uint8_t * MY_CLASS :: func_to_be_assigned_to_func_ptr ( uint8_t in_uint8 ) {
    return & array_data_member [ in_uint8 ] ;
}

void MY_CLASS :: func_to_make_use_of_func_ptr ( uint8_t in_uint8 ) {
    // 1st attempt :
    uint8_t * ptr_to_uint8_t = struct_with_func_ptr_data_member . func_ptr_member ( in_uint8 ) ;
    // error: must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘((MY_CLASS*)this)->MY_CLASS::struct_with_func_ptr_data_member.MY_CLASS::_struct_with_func_ptr::func_ptr_member (...)’, e.g. ‘(... ->* ((MY_CLASS*)this)->MY_CLASS::struct_with_func_ptr_data_member.MY_CLASS::_struct_with_func_ptr::func_ptr_member) (...)’
    
    // 2nd attempt :
    // uint8_t * ptr_to_uint8_t = struct_with_func_ptr_data_member .* func_ptr_member ( in_uint8 ) ;
    // error: ‘func_ptr_member’ was not declared in this scope; did you mean ‘func_ptr_type’?
    
    // 3rd attempt :
    // ( ( MY_CLASS * ) this ) -> MY_CLASS :: struct_with_func_ptr_data_member . MY_CLASS :: _struct_with_func_ptr :: func_ptr_member ( in_uint8 ) ;
    // error: must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘((MY_CLASS*)this)->MY_CLASS::struct_with_func_ptr_data_member.MY_CLASS::_struct_with_func_ptr::func_ptr_member (...)’, e.g. ‘(... ->* ((MY_CLASS*)this)->MY_CLASS::struct_with_func_ptr_data_member.MY_CLASS::_struct_with_func_ptr::func_ptr_member) (...)’
    
    // 4th attempt :
    // ( ( MY_CLASS * ) this ) -> MY_CLASS :: struct_with_func_ptr_data_member .* MY_CLASS :: _struct_with_func_ptr :: func_ptr_member ( in_uint8 ) ;
    // error: invalid use of non-static data member ‘MY_CLASS::_struct_with_func_ptr::func_ptr_member’
    
    std :: cout << "data member array value @ index " << unsigned ( in_uint8 ) << " = " << unsigned ( * ptr_to_uint8_t ) << std :: endl ;
}

MY_CLASS my_object ;

My driver code with the main function looks as follows :

#include <iostream>

#include <cstdint>

#include "my_header.hpp"

int main () {
    // my_object . struct_with_func_ptr_data_member . func_ptr_member = my_object . func_to_be_assigned_to_func_ptr ;
    // error: cannot convert ‘uint8_t* (MY_CLASS::*)(uint8_t)’ {aka ‘unsigned char* (MY_CLASS::*)(unsigned char)’} to ‘MY_CLASS::func_ptr_type’ {aka ‘unsigned char* (*)(unsigned char)’} in assignment
    // due to function pointer type definition, i.e. typedef uint8_t * ( * func_ptr_type ) ( uint8_t in_uint8 ) ;
    // modifying the function pointer type definition solves the error, i.e. typedef uint8_t * ( MY_CLASS :: * func_ptr_type ) ( uint8_t in_uint8 ) ; 
    
    my_object . struct_with_func_ptr_data_member . func_ptr_member = & MY_CLASS :: func_to_be_assigned_to_func_ptr ;
    // this seems to be acceptable for the compiler

    my_object . func_to_make_use_of_func_ptr ( 2 ) ;
}

I don't manage to compile the C++ program due to an error when trying to use the function pointer member within the struct data member to call the respective member function.

What is the correct way to do this ?


Solution

  • For any call to member pointer you always need extra brackets around the "function pointer" part due to operator precedence

    (this->*struct_with_func_ptr_data_member.func_ptr_member)(in_uint8);
    // or with extra brackes so that people don't have to look up precedence table even more
    (this->*(struct_with_func_ptr_data_member.func_ptr_member))(in_uint8);
    

    If it really has to be this convoluted (with member variable storing pointer to member function as own member), I'd prefer to simplify it with extra variable:

    const auto func_ptr = struct_with_func_ptr_data_member.func_ptr_member;
    uint8_t* ptr_to_uint8_t = (this->*func_ptr)(in_uint8);
    

    See it online