How to execute member-function-pointer with a smart pointer object?
First of all, your shown code and the error message does not match. For the given code you should be getting (from clang) following error message
error: left hand operand to .* must be a class compatible with the right hand operand, but is 'std::unique_ptr<Registers>'
(registerList.*setRegister)();
^
This can be solved by dereferencing the pointer(like in @Caleth's answer):
((*registerList).*setRegister)();
Now the error message that was shown in the question: no match for ‘operator->*
should be coming when you would have tried the following syntax.(Minimal reproducible code)
(registerList->*setRegister)();
This is because smart pointers do not have the pointer-to-member access operator defined in the standard. Therefore, you need to go for dereferencing the smart pointer via operator*
or by member function std::unique_ptr::get
, and call the member function.
Using the member std::unique_ptr::get
the correct syntax would be (See the live demo online)
(registerList.get()->*setRegister)()
That being said, if you have access to c++17 use unified version of function invoker std::invoke
to invoke the member function with the respective instance, by which you can forget about the (maybe)complicated syntax for operator->*
.
Your code has a couple of issues too:
The member function pointer type in your
opcodeLdWordRegister
is wrong.It should have beenreturn_type(Class_name::* variable_name)(/*parameters_types, if any*/)
Following is the fixed version.
#include <functional> // std::invoke void opcodeLdWordRegister(uint16_t(Registers:: * setRegister)()) // ^^^^^^^^^^^^^^^^^^^^^^^^^ >>> correct syntax { std::invoke(setRegister, registerList); // ^^^^^^^^^^^ member function // ^^^^^^^^^^^^ instance }
- Secondly, dereferencing of the uninitialised
registerList
pointer will cause UB.
Following is the demonstrative minimal complete example for the case: (See the live demo online)
#include <iostream>
#include <functional> // std::invoke
#include <memory> // std::unique_ptr
class Registers
{
uint16_t sp{2}; // member initialized with 2
public:
uint16_t getSP() const // function can be marked const as it does not alter the member
{
return this->sp;
}
};
auto registerList = std::make_unique<Registers>(); // initialized the pointer with default object
void opcodeLdWordRegister(uint16_t(Registers::*setRegister)() const)
// ^^^^^^^^^^^^^^^^^^^^^^^^^ correct syntax
{
std::cout << std::invoke(setRegister, registerList);
}
int main()
{
opcodeLdWordRegister(&Registers::getSP);
return 0;
}
Output:
2
If you don't have std::invoke
, you can still do what it would do, which is to dereference the (unique) pointer in the call site.
((*registerList).*setRegister)();