dimanche 4 janvier 2015

c++11 and std::bind: call virtual base-class method using a central command-mapper

I'd like to make a command Mapper that accepts commands of a certain type and hands them over to runtime-registered members of various sub-classes of a common "Bindable" class.


As the sub-class members are of different types, I struggle with programming a working Mapper class. How do I need to implement it to make it work?



#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;
}
};


The problematic 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;
};


The desired usage shall be:



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
}

Aucun commentaire:

Enregistrer un commentaire