Я пишу лексер для небольшой грамматики, и я нахожусь в точке, где мне нужно уменьшить количество дублируемого кода, который я пишу, поэтому внутри моего лексера я написал следующую функцию шаблона:
class Lexer
{
private:
std::optional<char> consume_if(Error err)
{
err_ = err;
return std::nullopt;
}
template <typename UnaryPredicate, typename ...Others>
std::optional<char> consume_if(Error err, UnaryPredicate p, Others... others)
{
if (eof())
{
return std::nullopt;
}
return p(peek()) == 0 ? consume_if(err, others...) : consume();
}
std::optional<std::string> parse_foo(); // see below
// I omitted functions I considered obvious. If needed, they can be added.
};
Теперь, текущее использование правила foo
(где foo = ALPHA *(ALPHA / DIGIT / "+" / "-" / "."
) должно быть (но, очевидно, проблематично c):
std::optional<std::string> Lexer::parse_foo()
{
static auto is_valid_punct = [](char c) { return c == '+' || c == '-' || c == '.'; };
std::string foo = consume_if(Err::INVALID_FOO, std::isalpha); // takes unsigned char, so this will be a problem
std::optional<char> c;
do
{
c = consume_if(Err::INVALID_FOO, std::isalpha, std::isdigit, is_valid_punct);
foo.push_back(*c); // but what do I do if c is nullopt?
} while (c);
return foo;
}
Теперь я знаю, что могу сделать эту работу с правильным if
с, но тогда это нарушит цель consume_if
.
Могу ли я написать шаблонную функцию c consume_if
? Нужны ли мне макросы вместо этого? Есть ли лучший подход ко всему этому, пожалуйста?