I'm creating a class called MessageableObject, that can register its own member functions in a map. These functions can be called from outside by calling sendMessage, providing a return type as a template parameter, and passing the name of the function, as well as the paramters as variadic arguments. I've seen something very similar to this done before, only the functions were not member functions of the class storing them.
Below is the code I've written thus far, as well as a test case that should succeed.
#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;
}
Currently, this code generates the following error twice:
C2064: term does not evaluate to a function taking n arguments
The first time with n being 0 for when I attempt to call foo
, and n being 2 for when I attempt to call bar
. Why are these errors occuring? And can I even implement this using the current syntax?
For reference, the version of this implementation that works on non-member functions can be found here: https://stackoverflow.com/a/33837343/962805
Any and all help is greatly appreciated. I'm not very knowledgeable on type erasure and member function binding. The intent for this is to create dynamic messaging a-la unity engine's GameObject.sendMessage
function.
Update: As according to skypjack's answer below, the above solution will break if the message call contains a variable. It can be fixed by changing Args&&...
in sendMessage to Args...
, however this poses a new issue: if a message is added to the map that contains a reference parameter (such as int bar(int&, int)
), it will not be able to be called implicitly. Calling sendMessage<int, int&, int>("bar", x, 2)
will function as intended.