ジェネリックコードは良いです。
TBuffer
from toXArgs
と from to のXResult
2つの convert メソッドを作成します。TBuffer
- 自動コマンド ラッパーを作成する
map
これらのラッパーに自動的にディスパッチする を実装します
関数へのポインタまたは継承のいずれかを使用して実行できます。継承の方が簡単だと思います...
class BaseCommand {
public:
virtual ~BaseCommand() {}
virtual TBuffer invoke(TBuffer const& tb) = 0;
};
template <typename Args, typename Result>
class CommandT: public BaseCommand {
public:
virtual TBuffer invoke(TBuffer const& tb) {
Args const a = from_buffer(tb, &a); // free function
Result const r = this->invoke(a);
return to_buffer(r); // free function
}
private:
virtual Result invoke(Args const&) = 0;
};
注: ごまかしとして、自動引数推定を取得するために に渡し&a
ますfrom_buffer
。ポインターは使用されていないことが予想されます。
ですから、引数と結果があるとしましょう (どちらint
も簡単です):
int from_buffer(TBuffer const& tb, int const*) {
return tb.asInt();
}
TBuffer to_buffer(int i) {
return TBuffer(i);
}
そして、以下を処理するコマンドを実装できますint
。
class IntCommand: public CommandT<int, int> {
virtual int invoke(int const& i) override { return i; }
};
よし、発送に移ろう。アイデアは、各コマンドをその ID に登録することです。
template <typename T>
std::unique_ptr<BaseCommand> make_command() { return std::unique_ptr<T>(new T()); }
static std::map<int, std::unique_ptr<BaseCommand>> Commands;
int main() {
Commands.insert(std::make_pair(1, make_command<IntCommand>()));
// lots of them...
// starts processing
}
そして、次のSocketHandler
ものがあります。
void SocketHandler::ReceiveCommand(int code, TBuffer const& a, TBuffer& r) {
typedef std::map<int, std::unique_ptr<BaseCommand>>::const_iterator const_it;
const_it it = Commands.find(code);
if (it == Commands.end()) {
std::cerr << "Unknown command: " << code << "\n";
throw std::runtime_error("Unknown command");
}
r = it->second->invoke(a);
}