"Called Object Type is Not a Function or Pointer" 使用 Typedef 和 类

"Called Object Type is Not a Function or Pointer" With Typedef and Classes

我正在尝试将我的 class' 函数 void write_log(String verbosity, Variant message); 传递给另一个 class,它将线程化事件循环 (ev.h)。 String 和 Variant 来自 godot 命名空间。

我使用 typedef 将 write_log 转换为使用定义 typedef void (godot::MQTT::*Logger)(godot::String, godot::Variant); 的 Logger 类型。此定义存储在被调用方 class 而不是调用方 class.

被调用的函数定义为void initialize(Logger logger);,然后用下面的代码调用。

libumqtt::Client client;
client.initialize(&MQTT::write_log);

我的主叫class是godot::MQTT,被叫class是libumqtt::Client

当我尝试使用 write_log 时出现错误。

void Client::initialize(Logger write_log) {
  ...

  write_log("error", "Initializing MQTT Client!!! TypeDEF!!!");

  ...
}

报错信息如下

➜  Godot-MQTT-Module git:(master) ✗ scons platform=osx bits=64
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o src/MQTT.os -c -g -O2 -arch x86_64 -std=c++17 -fPIC -I. -Igodot-cpp/godot_headers -Igodot-cpp/include -Igodot-cpp/include/core -Igodot-cpp/include/gen -Isrc -Ilibraries/libumqtt/src src/MQTT.cpp
g++ -o src/client.os -c -g -O2 -arch x86_64 -std=c++17 -fPIC -I. -Igodot-cpp/godot_headers -Igodot-cpp/include -Igodot-cpp/include/core -Igodot-cpp/include/gen -Isrc -Ilibraries/libumqtt/src src/client.cpp
src/client.cpp:120:14: error: called object type 'libumqtt::Client::Logger' (aka 'void (godot::MQTT::*)(godot::String, godot::Variant)') is not a function or function pointer
    write_log("error", "Initializing MQTT Client!!! TypeDEF!!!");
    ~~~~~~~~~^
1 error generated.
scons: *** [src/client.os] Error 1
scons: building terminated because of errors.

我一直在试图弄清楚为什么我不能让编译器识别函数指针,但到目前为止还没有这样的运气。我在乱用我的代码时收到诸如无法使用间接寻址等错误。

我还使用这些链接来帮助我学习如何使用 typedef 和传递函数指针:

编辑:未初始化的提到我的代码看起来正确,但发布的数量有限,我将链接粘贴到我的回购中的 classes 和 header 文件。这些链接被标记为这个特定的提交,所以即使我更新代码,内容也不会改变。另外,这个库是麻省理工学院的,所以你不用担心版权问题。

编辑 2:使用 ,我已经检查了我试图在被调用者 class 中使用 write_log 的变量类型,它 returns 符合我的预期它到。所以,我不知道为什么编译器看不到这是一个函数。我正在使用 C++17 来编译我的代码,而 C++14 也有同样的问题(C++11 在到达这里之前就中断了其他代码,因此它没有提供有用的结果)。

void (godot::MQTT::*)(godot::String, godot::Variant)

从您发布的有限代码片段来看,似乎没有任何错误。但是,如果在此函数调用之前的行中存在分号等语法问题,则已知 gcc/g++ 编译器会抛出此错误。

为了回答我自己的问题,我将重复并解释我编写的代码。

我们有两个 class 存储在两个文件中,MQTT.cpp 和 Client.cpp。 MQTT.cpp 具有命名空间 "godot" 和 class 名称 "MQTT"(因此,godot::MQTT::)。 Client.cpp 具有命名空间 "libumqtt" 和 class 名称 "Client"(因此,libumqtt::Client::)。

MQTT 有一个定义为 void write_log(String verbosity, Variant message); 的函数,它还有一个函数 initialize();。参数和 return 类型对初始化无关紧要。为了初始化客户端,我创建了一个 Client 对象,然后调用它自己的方法,也称为初始化。

// MQTT.cpp
String MQTT::initialize() {
    // ...

    // This code will initialize the Client class and pass the function `write_log` to the Client object.
    // `write_log` is marked as private in the header file MQTT.hpp.
    libumqtt::Client client;
    client.initialize(*this, &MQTT::write_log); // Initialize Instance of Client

    // ...
}

在Client.hpp中,我将初始化标记为public并添加了行void initialize(godot::MQTT& mqtt_class, Logger logger);。我还添加了 typedef typedef void (godot::MQTT::*Logger)(godot::String, godot::Variant);,这样我就可以将 write_log 的数据类型称为 Logger。

为了调用 write_log 函数,我使用了以下代码。

// Client.cpp
void Client::initialize(godot::MQTT& mqtt_class, Logger write_log) {
    // ...

    // Send Test Log
    // Why Invoke? - https://isocpp.org/wiki/faq/pointers-to-members#macro-for-ptr-to-memfn
    std::invoke(write_log, mqtt_class, "error", "Initializing MQTT Client!!! TypeDEF!!!");

    // ...
}

我做错的是我试图在不使用 invoke 的情况下调用指向成员函数的指针。因为我是 cpp 的新手,所以我不知道这样一个事实,如果它转到另一个不是我 class 的直接部分的函数,我就不能直接调用它。使用 invoke 比尝试使用 ((object).*(ptrToMember)) 更容易,后者的语法我还不完全理解。

我所做的是通过获取关键字 this 的指针来创建指向我的 class、godot::MQTT 的指针。然后,我通过变量 godot::MQTT& mqtt_class 创建对 this 提供的指针的引用。之后,调用函数 write_log 就像提供对调用 class 对象的引用,然后是调用 class 中函数的指针以及所需的参数一样简单调用函数。

因为我是 C++ 的菜鸟,有更多经验的人应该编辑这句话并解释为什么你需要在指向需要调用的函数的指针之上对调用对象的引用。