我想做一个命令Mapper,它接受某种类型的命令,并将它们交给一个公共Bindable类的各个子类的运行时注册成员。
由于子类成员的类型不同,我很难编写一个工作的Mapper类。我需要如何实现它才能使它发挥作用?
#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:
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;
};所希望的用途应为:
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
}发布于 2015-01-04 15:32:23
据我所见,当修复了两个小错误时,OP中的代码可以工作:
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循环期望在:的右侧提供迭代器范围的开始和结束,但搜索名称为begin和end的空闲函数或成员函数。因此,我们必须翻译std::pair::first -> begin()和std::pair::second -> end()。
当然,有一些库解决方案(例如,助推)。最低限度的解决办法可以是:
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
mMatch.second()->handleCmd(inv.cmd); // 2second of std::pair是一个公共数据成员,而不是一个成员函数:
mMatch.second->handleCmd(inv.cmd); // 2我建议您在CodeReview.SE上发布您的代码,因为有更通用的、更安全的(例如生命周期问题),并且可能更容易解决这个一般性问题。例如,有boost.signals2库;还有一个std::function包装器,它允许存储任意类型的对象,只要可以用特定的签名调用它们。
https://stackoverflow.com/questions/27766743
复制相似问题