Я думаю, что вам лучше всего представить файл в виде набора variant
с правильным типом команды. Например, допустим, у вас есть три варианта команд:
struct Constant {
short value;
};
struct UnaryOperation {
unsigned char opcode;
short value;
};
struct BinaryOperation {
unsigned char opcode;
short value1;
short value2;
};
Представление неизвестной команды. Если у вас есть неизвестная команда, вы можете представить ее как variant
из трех типов:
using Command = std::variant<Constant, UnaryOperation, BinaryOperation>;
Применение функции в зависимости от типа команды. Допустим, у вас есть разные функции для каждой команды:
short eval(Constant c) {
return c.value;
}
short eval(UnaryOperation u) {
switch(u.opcode) {
// stuff
}
}
short eval(BinaryOperation b) {
switch(b.opcode) {
// stuff
}
}
Мы можем использовать std::visit
для оценки произвольного Command
:
short evaluate_command(Command const& command) {
short output;
// This calls the right overload automatically
std::visit(command, [&](auto cmd) { output = eval(cmd); });
return output;
}
Парсинг команды.
Мы можем создать std::variant
автоматически из любого типа, для которого он определен. Это означает, что если вы предоставите способ выяснить, какая команда основана на файле, это довольно легко сделать.
enum class OpType : unsigned char {
ConstantOp, UnaryOp, BinaryOp
};
// Command can be automatically constructed from a Constant, a UnaryOperation, or a BinaryOperation
Command readFromStream(std::istream& i) {
OpType type;
unsigned char op;
short value, value2;
// Read the type of the operation
i >> (unsigned char&)type;
//Return either a Constant, a UnaryOperation, or a BinaryOperation
switch(type) {
case OpType::ConstantOp: {
i >> value;
return Constant{value};
}
case OpType::UnaryOp: {
i >> op >> value;
return UnaryOperation{op, value};
}
case OpType::BinaryOp {
i >> op >> value >> value2;
return BinaryOperation{op, value, value2};
}
}
}