gpt4 book ai didi

c++ - 存储和调用具有不同签名的成员函数的 unordered_map

转载 作者:行者123 更新时间:2023-11-30 03:33:31 25 4
gpt4 key购买 nike

我正在创建一个名为 MessageableObject 的类,它可以在映射中注册自己的成员函数。这些函数可以通过调用 sendMessage 从外部调用,提供返回类型作为模板参数,并传递函数的名称,以及作为可变参数的参数。我以前见过与此非常相似的东西,只是函数不是存储它们的类的成员函数。

下面是我到目前为止编写的代码,以及应该成功的测试用例。

#include <iostream>
#include <typeindex>
#include <typeinfo>
#include <unordered_map>

class MessageableObject
{
using _message_ptr = void(MessageableObject::*)(void);

std::unordered_map<const char*, std::pair<_message_ptr, std::type_index>> _message_map;

public:

MessageableObject()
{
}

template<typename F>
void addMessage(const char* name, F func)
{
auto type = std::type_index(typeid(func));
_message_map.insert(std::make_pair(name, std::make_pair((_message_ptr)func, type)));
}

template<typename R, typename... Args>
R sendMessage(const char* name, Args&&... args)
{
auto iter = _message_map.find(name);
assert(iter != _message_map.end());
auto type = iter->second;
auto func = reinterpret_cast<R(MessageableObject::*)(Args ...)>(type.first);
assert(type.second == std::type_index(typeid(func)));
return func(std::forward<Args>(args)...);
}

void foo()
{
std::cout << __FUNCTION__ << std::endl;
}

int bar(int i, int j)
{
std::cout << __FUNCTION__ << ' ' << i + j << std::endl;
return i + j;
}
};

int main()
{
MessageableObject obj;
obj.addMessage("foo", &MessageableObject::foo);
obj.addMessage("bar", &MessageableObject::bar);

obj.sendMessage<void>("foo");
int baz = obj.sendMessage<int>("bar", 1, 2);

return 0;
}

目前,这段代码会产生两次以下错误:

C2064: term does not evaluate to a function taking n arguments

当我尝试调用 foo 时第一次 n 为 0 , 当我尝试调用 bar 时 n 为 2 .为什么会出现这些错误?我什至可以使用当前语法实现它吗?

作为引用,可在此处找到适用于非成员函数的此实现版本:https://stackoverflow.com/a/33837343/962805

非常感谢任何帮助。我对类型删除和成员函数绑定(bind)不是很了解。这样做的目的是创建动态消息传递 a-la 统一引擎的 GameObject.sendMessage功能。

更新:根据 skypjack 在下面的回答,如果消息调用包含变量,上述解决方案将中断。可以通过更改 Args&&... 来修复在 sendMessage 到 Args... ,但是这带来了一个新问题:如果将消息添加到包含引用参数(例如 int bar(int&, int) )的映射中,它将无法被隐式调用。打电话sendMessage<int, int&, int>("bar", x, 2)将按预期运行。

最佳答案

如果您包括 <cassert>在文件的顶部并使用这个:

return (this->*func)(std::forward<Args>(args)...);

取而代之的是:

return func(std::forward<Args>(args)...);

它编译。<​​/p>

我不能说它有效,因为在我看来你很幸运地避免了 UB,而且它显然有效(这是一个完全有效的 UB) 会更合适。
问题是 bar有类型:

int(MessageableObject::*)(int i, int j);

然后你将它转换为:

void(MessageableObject::*)(void);

然后您将其转换回为您调用它的正确类型:

obj.sendMessage<int>("bar", 1, 2);

如果你这样做:

int x = 1;
obj.sendMessage<int>("bar", x, 2);

你会执行一个类型转换:

int (MessageableObject::*)(int &i, int j);

错误 返回类型会发生类似的事情。这些都是UB。因此,从我的角度来看,在生产环境中使用它的解决方案太弱了。

关于c++ - 存储和调用具有不同签名的成员函数的 unordered_map,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42802413/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com