【问题标题】:"Called Object Type is Not a Function or Pointer" With Typedef and Classes带有 Typedef 和类的“被调用的对象类型不是函数或指针”
【发布时间】:2020-04-01 15:00:38
【问题描述】:

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

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

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

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

我的调用类是godot::MQTT,被调用类是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 并传递函数指针:

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

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

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

【问题讨论】:

  • 不知道这样有没有帮助,但是原来的write_log函数在头文件中被标记为私有的。
  • 我将函数标记为私有,因为从 write_log 调用的记录器类是从游戏引擎传入的。 logger 类是使用 GDScript 编写的。我试图传递给我的第二堂课的原始 write_log 工作得很好,它只是不能静态工作。
  • 我设法让它工作。它与传递类本身的引用有关。我使用 std::invoke 来调用该函数。我稍后会发布我所做的,但是对于现在想查看的人,请查看此Github link

标签: c++ godot


【解决方案1】:

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

【讨论】:

  • 我之前检查过线路,它们没有损坏。它们只是帮助设置使用 libev 的变量。
【解决方案2】:

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

我们有两个类,它们存储在 MQTT.cpp 和 Client.cpp 这两个文件中。 MQTT.cpp 具有命名空间“godot”和类名“MQTT”(因此,godot::MQTT::)。 Client.cpp 具有命名空间“libumqtt”和类名“Client”(因此,libumqtt::Client::)。

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

// 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 中,我将初始化标记为公共并添加了行 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!!!");

    // ...
}

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

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

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

【讨论】:

    猜你喜欢
    • 2021-11-21
    • 1970-01-01
    • 1970-01-01
    • 2018-06-02
    • 2012-06-22
    • 2013-09-09
    • 2012-05-28
    • 1970-01-01
    相关资源
    最近更新 更多