Кажется, вы хотите полагаться на имя, чтобы знать, какой аргумент передать, поэтому плагины должны знать, как другие плагины называют свой метод и какой аргумент передавать ...
Тогда, кажется, проще предоставить способ получения плагинов:
AppInterface* GetPlugin(const char* name);
и до плагина dynamic_cast
его до того, который требуется, и вызывать напрямую любой метод на нем. Например:
struct SomePlugin : AppInterface
{
// ...
void print();
int foo(int n);
};
struct MyPlugin : AppInterface
{
// ...
void bar() {
auto* plugin = dynamic_cast<SomePlugIn>(GetPlugin("SomePlugIn"));
if (plugin) {
plugin->print();
int n = plugin->foo(42);
// ...
}
}
};
С некоторыми соглашениями, как static const char* Plugin::Name
, вы можете предоставить dynamic_cast в функции напрямую:
template <typename Plugin>
Plugin* GetPlugin() { return dynamic_cast<Plugin>(GetPlugin(Plugin::Name)); }
Если вы действительно хотите, чтобы ваш интерфейс регистрировал функции и вызывал их, вы можете использовать std::any
: /
std::map<std::string, std::any> listenerMap;
template<typename Sig>
void register(const char* key, std::function<Sig> f);
{
listenerMap[key] = f;
}
template<typename Sig, typename ...Args>
void broadcast(const char* key, Args&& ... args)
{
auto it = listenerMap.find(key);
if (it != listenerMap.end()) {
auto* f = std::any_cast<std::function<Sig>>(&it->second);
if (f) {
(*f)(std::forward<Args>(args)...);
}
}
}
При использовании, аналогичном:
struct MyPlugin : AppInterface
{
// ...
void print() const;
void foo(int) const;
void my_register() {
register<void()>("my_print", [this](){ this->print(); });
register<void(int)>("foo", [this](int n){ this->foo(n); });
}
void call_me() {
broadcast<void()>("my_print");
broadcast<void(int)>("foo", 42);
}
};
Вы должны передать Sig
в broadcast
и не допускать удержания из Args
в целях безопасности.
Передача std::string&
вместо const std::string&
или const char*
вместо std::string
приведет к ожидаемому изменению std::function<void(const std::string&)>
к std::function<void(std::string&)>
, поэтому std::any_cast
завершится неудачей.