以后如何存储和调用不同类的成员函数,这些成员函数是从同一接口类继承的

时间:2018-11-06 17:51:00

标签: c++ qt functor

我正在创建一个应用程序,目前可以通过从接口类(称为AppInterface)继承并由Qt的插件加载器系统加载的几个插件进行扩展。可以使用dll为每个插件提供被视为核心的类的全局静态实例。

现在,要在插件之间交换数据,我计划在核心中创建2个函数,一个函数将侦听器函数指针存储在映射中的键下,另一个函数调用存储的函数 在键下,并带有参数。

std::map<char*,std::list<void*> > listenerMap;
template<typename... Args, typename T>
void listen(char* key,  T *inst, void (T::*listenerSlot)(Args...))
{
get the functor list with key from the listener map and append the functor.
}
template<typename ...Args> 
void broadcast (char* key, Args... args)
{
get the list with key from the listener map and invoke all the functors with the given arguments.
}

我还没有找到一种方法来存储仿函数及其类对象,并在以后调用它们。函子参数不是固定的,它们会因函数而异,除非它们在侦听器映射中的同一键下。

是否需要更改广播和侦听功能的结构,或者有更好的主意来调用存储的成员函数?

还是我可以使用每个插件都继承的AppInterface?

NB:出于某些原因,我决定不使用Qt信号槽系统,因为我希望AppInterface成为基类而不是QObject。

1 个答案:

答案 0 :(得分:1)

似乎您想依靠名称来知道要传递的参数,因此插件应该知道其他插件如何命名其方法以及要传递的参数...

然后,提供一种检索插件的方法似乎更简单:

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会失败