Я не буду давать ответ, но Стандартное Плохое Решение включает в себя использование переключателя или определения случая (или просто хорошего старомодного каскадного ввода-вывода). Немного лучшее решение предполагает использование таблицы указателей функций, а, вероятно, лучшее решение предполагает использование полиморфизма.
Последние двадцать лет эволюции интерпретаторов можно рассматривать как движение по другому пути - полиморфизм (например, наивные метациркулярные интерпретаторы Smalltalk) на функции указателей (реализации наивного lisp, многопоточного кода, C ++) для переключения ( наивные интерпретаторы байт-кода), а затем и далее в JIT и т. д., которые либо требуют очень больших классов, либо (в однополиморфных языках) двойной диспетчеризации, что сводит полиморфизм к регистру типов, и вы возвращаетесь на этап один. Какое определение 'best' используется здесь?
Для простых вещей полиморфное решение в порядке - вот то, что я сделал ранее , но либо стек и байт-код / переключатель, либо использование компилятора среды выполнения обычно лучше, если вы, скажем, строите функцию с несколькими тысячами точек данных.
Динамические выражения
Если вы хотите получить строку от пользователя и построить на ее основе выражение, возможно, вам подойдет Библиотека математических выражений C ++ ?
template<typename T>
void trig_function()
{
std::string expression_string = "clamp(-1.0,sin(2 * pi * x) + cos(x / 2 * pi),+1.0)";
T x;
exprtk::symbol_table<T> symbol_table;
symbol_table.add_variable("x",x);
symbol_table.add_constants();
exprtk::expression<T> expression;
expression.register_symbol_table(symbol_table);
exprtk::parser<T> parser;
parser.compile(expression_string,expression);
for (x = T(-5.0); x <= T(+5.0); x += 0.001)
{
T y = expression.value();
printf("%19.15f\t%19.15f\n",x,y);
}
}
] Также есть возможность встроить язык сценариев, такой как Lua или Python , что даст вам (даже) больше возможностей. Это то, что следует учитывать, если вы пишете игру, поскольку вы, вероятно, захотите написать скрипт для ее больших частей.
Если вы используете Qt , вы можете использовать QtScript (Javascript-ish) для запуска выражений, которые считывают (статические или динамические) свойства из ваших объектов, производных от QObject.
Использование одного из вышеперечисленных избавляет вас от необходимости писать свой собственный анализатор, AST и вычислитель, однако для небольшой набор операторов, которого не следует Если вы используете Boost.Spirit или какую-нибудь другую достойную библиотеку синтаксического анализа, будет слишком сложно что-то взломать.
Статические выражения
Для выбора между набором предопределенных выражений (т.е. известных во время компиляции) , вы должны сохранить выражение в полиморфном функциональном объекте.
Для C ++ 11, если это доступно, используйте std :: function
и лямбда-выражения.
std::function<bool (int, int)> expr = [](int a, int b) { a*2 < b };
Для более ранних компиляторов я рекомендую функцию и привязку либо в Boost (boost: :), либо в C ++ 0x TR1 (std: :), в зависимости от вашего компилятора. Также здесь может помочь Boost.Lambda, поскольку он позволяет создавать и сохранять выражения для последующей оценки. Однако, если вы не знакомы с C ++ и шаблонами (или функциональным программированием), это, скорее всего, вас немного напугает.
С этим вы можете написать
using namespace boost::lambda;
boost::function<bool (int, int)> myexpr1 = (_1 + _2) > 20;
boost::function<bool (int, int)> myexpr2 = (_1 * _2) > 42;
std::cout << myexpr1(4,7) << " " << myexpr2(2,5);
с помощью bind, это ' d выглядит так:
boost::function<bool (Player&)> check = bind(&Player::getHealth, _1) > 20;
Player p1;
if (check(p1)) { dostuff(); }
check = bind(&Player::getGold, _1) < 42;
if (check(p1)) { doOtherStuff(); }
No, there isn't anything like that. Perhaps an expression class is a little too abstract. What about defining various Goal classes with an IsReached() method?
Не существует стандартного способа компиляции выражений во время выполнения. Вам придется сделать это другим способом.
Вы можете рассмотреть возможность использования языка сценариев, такого как Lua или Python, и встроить его в свой C ++. Это даст вашим игрокам возможность программировать так, как вы хотите.
C ++ не имеет этого как части языка - во время выполнения нет возможности получить доступ к тому же материалу, который анализировал вашу программу.
Я уверен однако существует множество сторонних библиотек арифметического анализатора, которые вы можете использовать.
Я думаю, вы можете определить свой собственный класс и обойти его, используя ключевое слово assert, но, возможно, я неправильно понял вопрос.
http : //www.cplusplus.com/reference/clibrary/cassert/assert/
Почему бы не создать свой собственный классы выражений?
class GoalBase
{
virtual bool goal() = 0;
};
class Enemies : public GoalBase
{
// ..
private:
int enemies_;
public:
Enemies(int start) : enemies_(start) {}
void kill() { if (enemies_) --enemies_; }
bool goal() { return enemies_ == 0; }
};
int main()
{
Enemies enemiesToKill(5);
enemiesToKill.kill();
// ..
if (enemiesToKill.goal()) {
// ..
}
return 0;
}
Другие классы могут иметь другие методы, параметры, операторы и т. д. Используйте свое воображение.
Кажется, не так много признанных библиотек оценки выражений для C ++. Я написал свой собственный для CSVfix , который вы можете убедить, просмотрев файлы a_expr.h
и a_expr.cpp
в библиотеке ALib, которая является частью CSVfix. источник. Оценщику нечего рекомендовать, за исключением того, что он выполняет свою работу и (IMHO) довольно прост для понимания.
К сожалению, в настоящее время нет общедоступной документации для оценщика, и, по моему собственному практическому правилу, то, что не задокументировано, не может быть повторно использовано. Однако модульные тесты показывают, как его можно использовать, а исходный код может дать вам некоторые идеи по реализации вашего собственного оценщика, если вы захотите.
за исключением того, что он выполняет свою работу и (ИМХО) довольно прост для понимания.К сожалению, в настоящее время нет общедоступной документации для оценщика, и, по моему собственному практическому правилу, то, что не задокументировано, не может быть повторно использовано. Однако модульные тесты показывают, как его можно использовать, а исходный код может дать вам некоторые идеи по реализации вашего собственного оценщика, если вы захотите.
за исключением того, что он выполняет свою работу и (ИМХО) довольно прост для понимания.К сожалению, в настоящее время нет общедоступной документации для оценщика, и, по моему собственному практическому правилу, то, что не задокументировано, не может быть повторно использовано. Однако модульные тесты показывают, как его можно использовать, а исходный код может дать вам некоторые идеи по реализации вашего собственного оценщика, если вы захотите.
В C ++ нет стандартного способа сделать это. Одно из решений - написать собственный парсер.
Еще одно решение, которое я бы порекомендовал: встроить интерпретатор Lua в вашу программу. Lua - это простой, но мощный язык программирования, который также имеет чрезвычайно легкий (<300 КБ) и простой в использовании интерпретатор. Прочтите вводную статью здесь: http://www.ibm.com/developerworks/linux/library/l-embed-lua/index.html
Внедрение Lua в вашу игру имеет ряд приятных побочных преимуществ. :