如何使用智能指针对象执行成员函数指针?

toa*_*fan 6 c++ member-function-pointers smart-pointers unique-ptr c++11

我正在尝试member-function使用智能指针实例执行类的。该函数的地址通过值传递,我想通过相应类的智能指针实例调用该值。

我已经试过了:

(registerList.*setRegister)();
Run Code Online (Sandbox Code Playgroud)

但是它出错了:

no match for ‘operator->*
Run Code Online (Sandbox Code Playgroud)

Register 类成员函数:

uint16_t Registers::getSP()
{
    return this->sp;
}
Run Code Online (Sandbox Code Playgroud)

代码段:

std::unique_ptr<Registers> registerList;

SetRegisteropcodeLdWordRegister(&Registers::getSP)

void opcodeLdWordRegister(uint16_t (*Registers::setRegister)()) 
{
        (registerList.*setRegister)();
}
Run Code Online (Sandbox Code Playgroud)

JeJ*_*eJo 5

首先,您显示的代码和错误消息不匹配。对于给定的代码,您应该(从 clang)获得以下错误消息

error: left hand operand to .* must be a class compatible with the right hand operand, but is 'std::unique_ptr<Registers>'    
   (registerList.*setRegister)();
            ^
Run Code Online (Sandbox Code Playgroud)

这可以通过取消引用指针来解决(如@Caleth 的回答):

((*registerList).*setRegister)();
Run Code Online (Sandbox Code Playgroud)

现在问题中显示的错误消息:no match for ‘operator->*当您尝试以下语法时应该会出现。(最小可重现代码

(registerList->*setRegister)();
Run Code Online (Sandbox Code Playgroud)

这是因为智能指针没有标准中定义的指针成员访问运算符。因此,您需要operator*通过成员函数或通过成员函数取消引用智能指针std::unique_ptr::get,并调用成员函数。

使用成员std::unique_ptr::get的正确语法是参见在线演示

(registerList.get()->*setRegister)()
Run Code Online (Sandbox Code Playgroud)

话虽如此,如果您可以访问使用统一版本的函数调用程序std::invoke来调用具有相应实例的成员函数,这样您就可以忘记operator->*.

您的代码也有几个问题:

  • 你的成员函数指针类型opcodeLdWordRegister是错误的。应该是

    error: left hand operand to .* must be a class compatible with the right hand operand, but is 'std::unique_ptr<Registers>'    
       (registerList.*setRegister)();
                ^
    
    Run Code Online (Sandbox Code Playgroud)

    以下是固定版本。

    ((*registerList).*setRegister)();
    
    Run Code Online (Sandbox Code Playgroud)
  • 其次,取消引用未初始化的registerList指针将导致 UB。

以下是为案件的示范性最小的完整的例子:见现场演示在线

#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;
}
Run Code Online (Sandbox Code Playgroud)

输出

2
Run Code Online (Sandbox Code Playgroud)

  • `std::invoke` 的目的是统一调用语法。在这种情况下,它是“如果`t1`不满足前面的项目,则`INVOKE(f, t1, t2, ..., tN)`相当于`((*t1).*f)(t2, . ..,tN)`。” (3认同)
  • @Evg我认为,不需要:https://wandbox.org/permlink/jz9jQQfdJj6R0fjO (2认同)
  • 我懂了。`std::invoke` 将为我们带来精彩。 (2认同)