首页 文章

std :: function的容器,具有多态类型作为函数参数

提问于
浏览
1

我想要“另一个”回调注册的东西 . 扩展公共基本事件类型的不同事件类型将触发相关的回调函数 .

这是初稿或想法

#include <functional>
#include <iostream>
#include <unordered_map>

class BaseEvent 
{ 
public: 
    virtual ~BaseEvent() {}
};

class DerivedEvent_1 : public BaseEvent {};
class DerivedEvent_2 : public BaseEvent {};


// a container holding callback functions
std::unordered_map<size_t/*event*/, std::function<void(BaseEvent)>/*callback*/> _callbacks;


// register callback funtion associated with specific event
template<typename EVT>  
void registerCallback(std::function<void(EVT)> cb)
{
    std::cout << "store callback associated with event " << typeid(EVT).name() << " [" << typeid(EVT).hash_code() << "]" << std::endl;
    //_functions[ typeid(EVT).hash_code() ] = cb; // FIXME
}


// trigger callback function
void triggerCallback(const BaseEvent* e)
{
    std::cout << "trigger callback with event " << typeid(*e).name() << " [" << typeid(*e).hash_code() << "]" << std::endl;
    //_functions[ typeid(*e).hash_code() ] (*e); // FIXME
}

// callback function for DerivedEvent_1
void callback_1(DerivedEvent_1 event_1)
{
    std::cout << "callback_1 called" << std::endl;
}

// callback function for DerivedEvent_2
void callback_2(DerivedEvent_2 event_2)
{
    std::cout << "callback_2 called" << std::endl;
}


int main(int argc, char *argv[])
{
    registerCallback<DerivedEvent_1>( [](DerivedEvent_1 e) { callback_1(e); } );
    registerCallback<DerivedEvent_2>( [](DerivedEvent_2 e) { callback_2(e); } );


    DerivedEvent_1 e1;
    DerivedEvent_2 e2;

    triggerCallback(&e1);
    triggerCallback(&e2);

    return 1;
}

到目前为止没有真正实施的那么好......

$ g++ -std=c++11 -o testStdFunction testStdFunvtion.cpp 
$ ./testStdFunction 
store callback associated with event 14DerivedEvent_1 [4527193776]
store callback associated with event 14DerivedEvent_2 [4527193680]
trigger callback with event 14DerivedEvent_1 [4527193776]
trigger callback with event 14DerivedEvent_2 [4527193680]

情况和问题是:

  • 事件是类或结构,可以具有特定属性作为有效负载

  • 我想保留回调函数(例如void callback_1(DerivedEvent_1 event_1)而没有指针作为参数 . 原因:这些回调函数可能已存在于代码库中,我不想更改它或制作额外的包装器 .

  • 如何让_callbacks映射为具有不同签名的std :: function?即让_callbacks映射可以保存std :: function

目的是修复registerCallback和triggerCallback中的FIXME代码 . 因此在运行代码后它们将如下所示

$ g++ -std=c++11 -o testStdFunction testStdFunvtion.cpp 
$ ./testStdFunction 
store callback associated with event 14DerivedEvent_1 [4527193776]
store callback associated with event 14DerivedEvent_2 [4527193680]
trigger callback with event 14DerivedEvent_1 [4527193776]
callback_1 called
trigger callback with event 14DerivedEvent_2 [4527193680]
callback_2 called

1 回答

  • 1

    您可以使用已擦除的包装 .
    以下代码准确打印OP在问题中发布的消息 .
    键类是 BaseWrapper ,模板类是 Wrapper .
    此外,我稍微改变了代码周围的功能签名,让它正常工作 .

    #include <functional>
    #include <iostream>
    #include <unordered_map>
    #include<memory>
    #include<utility>
    
    class BaseEvent 
    { 
    public: 
        virtual ~BaseEvent() {}
    };
    
    class DerivedEvent_1 : public BaseEvent {};
    class DerivedEvent_2 : public BaseEvent {};
    
    struct BaseWrapper {
        virtual void operator()(const BaseEvent *) = 0;
    };
    
    template<typename T>
    struct Wrapper: BaseWrapper {
        std::function<void(T)> fn;
        void operator()(const BaseEvent *e) {
            fn(*static_cast<const T*>(e));
        }
    };
    
    
    // a container holding callback functions
    std::unordered_map<size_t/*event*/, std::unique_ptr<BaseWrapper>/*callback*/> _functions;
    
    
    // register callback funtion associated with specific event
    template<typename EVT>  
    void registerCallback(std::function<void(const EVT &)> cb)
    {
        std::cout << "store callback associated with event " << typeid(EVT).name() << " [" << typeid(EVT).hash_code() << "]" << std::endl;
        auto w = std::make_unique<Wrapper<EVT>>();
        w->fn = cb;
        _functions[ typeid(EVT).hash_code() ] = std::move(w);
    }
    
    
    // trigger callback function
    void triggerCallback(const BaseEvent* e)
    {
        std::cout << "trigger callback with event " << typeid(*e).name() << " [" << typeid(*e).hash_code() << "]" << std::endl;
        (*_functions[ typeid(*e).hash_code() ] )(e);
    }
    
    // callback function for DerivedEvent_1
    void callback_1(const DerivedEvent_1 &event_1)
    {
        std::cout << "callback_1 called" << std::endl;
    }
    
    // callback function for DerivedEvent_2
    void callback_2(const DerivedEvent_2 &event_2)
    {
        std::cout << "callback_2 called" << std::endl;
    }
    
    int main(int argc, char *argv[])
    {
        registerCallback<DerivedEvent_1>( [](DerivedEvent_1 e) { callback_1(e); } );
        registerCallback<DerivedEvent_2>( [](DerivedEvent_2 e) { callback_2(e); } );
    
        DerivedEvent_1 e1;
        DerivedEvent_2 e2;
    
        triggerCallback(&e1);
        triggerCallback(&e2);
    
        return 1;
    }
    

    可以在性能方面改进包装器(例如,使用静态成员方法而不是多态,留给读者作为练习) .
    解决方案背后的基本思想是所谓的 type-erasure .
    Google将帮助您找到有关该细节的更多详细信息 .

相关问题