在地图中存储通用回调

Posted

技术标签:

【中文标题】在地图中存储通用回调【英文标题】:Store generic callback in a map 【发布时间】:2020-04-19 14:13:17 【问题描述】:

我想创建一个 id / 通用回调映射,但我不知道这是否可行。我的想法是这样的: 不同的国王od对象

class Class1

public:
    bool run(const int &temp)
        std::cout << "worker1:" << temp << std::endl;
        return 0;
    
;
class Class2

public:
    bool run(const std::string &temp)
        std::cout << "worker2:" << temp << std::endl;
        return 0;
    
;

回调对象的模板:

template <typename ReturnType, typename... Args>
class Callback

private:
    std::function<ReturnType> _function;

public:
    Callback(std::function < ReturnType(Args...)> function) 
        : _function(function)

    auto run(Args... args)
    
        return function(std::forward<Args>(args)...);
    
;

使用示例

int main() 
    Class1 class1;
    Class2 class2;

    std::map<int, Callback> cbs;

    cbs[1] = std::bind(&Class1::run, &class1, std::placeholders::_1));
    cbs[2] = std::bind(&Class1::run, &class1, std::placeholders::_1));

     cbs[1].run(1);
     cbs[2].run("string msg");           

【问题讨论】:

假设你设法实现了你想要的。你打算如何使用它?特别是,调用代码如何知道何时将int 以及何时将string 传递给回调? @IgorTandetnik:我在下面的工厂示例中遇到了确切的问题,并使用可变参数模板和std::any 解决了它 谢谢你的回答..这只是一个例子..我想将它与不同的地图一起使用..例如使用地图来存储各种接受字符串的回调 这很简单。 std::map&lt;int, std::function&lt;void(std::string)&gt;&gt; 应该这样做。 【参考方案1】:

也许你可以用std::any实现一些东西

我创建了工厂,在其中存储了带有地图中任何签名的函数。

请看一下,如果它可以给你一个想法。否则我会删除这个答案

#include <iostream>
#include <map>
#include <utility>
#include <any>


// Some demo classes ----------------------------------------------------------------------------------
struct Base 
    Base(int d) : data(d) ;
    virtual ~Base()  std::cout << "Destructor Base\n"; 
    virtual void print()  std::cout << "Print Base\n"; 
    int data;
;
struct Child1 : public Base 
    Child1(int d, std::string s) : Base(d)  std::cout << "Constructor Child1 " << d << " " << s << "\n"; 
    virtual ~Child1()  std::cout << "Destructor Child1\n"; 
    virtual void print()  std::cout << "Print Child1: " << data << "\n"; 
;
struct Child2 : public Base 
    Child2(int d, char c, long l) : Base(d)  std::cout << "Constructor Child2 " << d << " " << c << " " << l << "\n"; 
    virtual ~Child2()  std::cout << "Destructor Child2\n"; 
    virtual void print()  std::cout << "Print Child2: " << data << "\n"; 
;
struct Child3 : public Base 
    Child3(int d, long l, char c, std::string s) : Base(d)  std::cout << "Constructor Child3 " << d << " " << l << " " << c << " " << s << "\n"; 
    virtual ~Child3()  std::cout << "Destructor Child3\n"; 
    virtual void print()  std::cout << "Print Child3: " << data << "\n"; 
;



using UPTRB = std::unique_ptr<Base>;


template <class Child, typename ...Args>
UPTRB createClass(Args...args)  return std::make_unique<Child>(args...); 

// The Factory ----------------------------------------------------------------------------------------
template <class Key, class Object>
class Factory

    std::map<Key, std::any> selector;
public:
    Factory() : selector() 
    Factory(std::initializer_list<std::pair<const Key, std::any>> il) : selector(il) 

    template<typename Function>
    void add(Key key, Function&& someFunction)  selector[key] = std::any(someFunction); ;

    template <typename ... Args>
    Object create(Key key, Args ... args) 
        if (selector.find(key) != selector.end()) 
            return std::any_cast<std::add_pointer_t<Object(Args ...)>>(selector[key])(args...);
        
        else return nullptr;
    
;

int main()

    Factory<int, UPTRB> factory
        1, createClass<Child1, int, std::string>,
        2, createClass<Child2, int, char, long>
    ;
    factory.add(3, createClass<Child3, int, long, char, std::string>);


    // Some test values
    std::string s1(" Hello1 "); std::string s3(" Hello3 ");
    int i = 1;  const int ci = 1;   int& ri = i;    const int& cri = i;   int&& rri = 1;

    UPTRB b1 = factory.create(1, 1, s1);
    UPTRB b2 = factory.create(2, 2, '2', 2L);
    UPTRB b3 = factory.create(3, 3, 3L, '3', s3);

    b1->print();
    b2->print();
    b3->print();
    b1 = factory.create(2, 4, '4', 4L);
    b1->print();
    return 0;

【讨论】:

谢谢你的例子。我喜欢它,但我不能在我的项目中使用,因为例如 Class1 class1 和 Class2 class2 是完全不同的。所以我不能使用基类

以上是关于在地图中存储通用回调的主要内容,如果未能解决你的问题,请参考以下文章

使用不同签名的通用回调函数

C++ 通用回调实现

所有地图变体的通用打印功能 C++ STL

将每个与 node-orm2 一起使用的通用回调

如何在通用 Windows 平台地图控件上设置 LocationRectangle?

使用参数 c++11 绑定通用回调