首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >c++11:使用中心命令映射程序调用虚拟基类方法

c++11:使用中心命令映射程序调用虚拟基类方法
EN

Stack Overflow用户
提问于 2015-01-04 14:53:27
回答 1查看 85关注 0票数 1

我想做一个命令Mapper,它接受某种类型的命令,并将它们交给一个公共Bindable类的各个子类的运行时注册成员。

由于子类成员的类型不同,我很难编写一个工作的Mapper类。我需要如何实现它才能使它发挥作用?

代码语言:javascript
复制
#include <iostream>     // std::cout
#include <functional>   // std::bind
#include <map>          // std::map
#include <vector>       // std::vector

struct Command {
    int cmdNum;
    int numArgs;
    std::vector<int> args;
};

struct Invocation {
    enum Source {
        SOURCE_X = 0, SOURCE_Y, SOURCE_Z,
        SOURCE_END
    };
    Source src;
    Command cmd;
};

struct Bindable {
    virtual void handleCmd(Command Cmd) = 0;
};

struct A : Bindable {
    void handleCmd (Command cmd) {
        std::cout << "called handler-method of class A" <<std::endl;
        std::cout << "cmdNum: " << cmd.cmdNum <<std::endl;
    }
};

struct B : Bindable {
    void handleCmd (Command cmd) {
        std::cout << "called handler-method of class B" <<std::endl;
        std::cout << "cmdNum: " << cmd.cmdNum <<std::endl;
    }
};

有问题的Mapper:

代码语言:javascript
复制
struct Mapper {
    void bindCmd(Command cmd, Bindable* mBindable) {
        //Fill a multimap with cmd.cmdNum as keys and mBindable as values
    }

    //Send cmd to each registered Bindable for the respective cmdNum
    void handleInv(Invocation inv) {
        auto mMatches = mBinds.equal_range(inv.cmd.cmdNum);

        for(auto mMatch : mMatches) {
            mMatch.second()->handleCmd(inv.cmd);
        }
    }

private:
    std::multimap<int, Bindable*> mBinds;
};

所希望的用途应为:

代码语言:javascript
复制
int main() {
    A a;
    B b;

    Command cmdA = {200, 4, {1,2,3,4}};
    Command cmdB = {400, 3, {3,2,1}};
    Command cmdC = {600, 2, {8,9}};

    Invocation invA = {Invocation::SOURCE_X, cmdA};
    Invocation invB = {Invocation::SOURCE_Z, cmdB};
    Invocation invC = {Invocation::SOURCE_Z, cmdC};

    Mapper mMapper;

    //Register Commands
    mMapper.bindCmd(cmdA, &a);
    mMapper.bindCmd(cmdB, &a);
    mMapper.bindCmd(cmdA, &b);
    mMapper.bindCmd(cmdC, &b);

    //React to incoming Invocations
    mMapper.handleInv(invA); //Call handleCmd of a and b
    mMapper.handleInv(invB); //Call handleCmd of a
    mMapper.handleInv(invC); //Call handleCmd of b
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-01-04 15:32:23

据我所见,当修复了两个小错误时,OP中的代码可以工作:

代码语言:javascript
复制
std::multimap<int, Bindable*> mBinds;

void handleInv(Invocation inv) {
    auto mMatches = mBinds.equal_range(inv.cmd.cmdNum);

    for(auto mMatch : mMatches) {            // 1
        mMatch.second()->handleCmd(inv.cmd); // 2
    }
}

1

std::multimap<K,V>::equal_range返回迭代器的std::pair,其中成员first指定开始,成员second返回迭代器范围的结束。

基于范围的for循环期望在:的右侧提供迭代器范围的开始和结束,但搜索名称为beginend的空闲函数或成员函数。因此,我们必须翻译std::pair::first -> begin()std::pair::second -> end()

当然,有一些库解决方案(例如,助推)。最低限度的解决办法可以是:

代码语言:javascript
复制
template<typename It>
struct iterator_pair_range
{
    It b;
    It e;

    It begin() const { return b; }
    It end() const { return e; }
};

template<typename It>
auto make_iterator_pair_range(std::pair<It, It> const& p)
    -> iterator_pair_range<It>
{ return {p.first, p.second}; }

for(auto mMatch : make_iterator_pair_range(mMatches)) {

2

代码语言:javascript
复制
mMatch.second()->handleCmd(inv.cmd); // 2

second of std::pair是一个公共数据成员,而不是一个成员函数:

代码语言:javascript
复制
mMatch.second->handleCmd(inv.cmd); // 2

我建议您在CodeReview.SE上发布您的代码,因为有更通用的、更安全的(例如生命周期问题),并且可能更容易解决这个一般性问题。例如,有boost.signals2库;还有一个std::function包装器,它允许存储任意类型的对象,只要可以用特定的签名调用它们。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27766743

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档