Здесь я пытаюсь преобразовать строковый литерал в число, где базовый спецификатор является динамическим:
#include <string>
#include <boost/spirit/home/x3.hpp>
namespace ast {
struct literal {
enum base_specifier { bin, oct, hex };
base_specifier base;
std::string literal;
};
}
namespace x3 = boost::spirit::x3;
template<typename T>
auto as = [](auto p) { return x3::rule<struct _, T>{} = x3::as_parser(p); };
template <typename TargetT>
std::pair<bool, TargetT> convert(ast::literal const& node)
{
auto const parse = [](ast::literal::base_specifier base, auto const& literal) {
using base_specifier = ast::literal::base_specifier;
auto const parser = [](base_specifier base) {
switch(base) {
case base_specifier::bin: {
using parser_type = x3::uint_parser<TargetT, 2>;
parser_type const p = parser_type{};
return as<TargetT>( p );
}
case base_specifier::oct: {
using parser_type = x3::uint_parser<TargetT, 8>;
parser_type const p = parser_type{};
return as<TargetT>( p );
}
case base_specifier::hex: {
using parser_type = x3::uint_parser<TargetT, 16>;
parser_type const p = parser_type{};
return as<TargetT>( p );
}
default:
abort();
}
};
auto iter = std::begin(literal);
auto const end = std::cend(literal);
TargetT attribute;
bool parse_ok = x3::parse(iter, end, parser(base), attribute);
return std::make_tuple(parse_ok && (iter == end), attribute);
};
// other complex stuff here
return parse(node.base, node.literal);
}
int main()
{
ast::literal literal{ ast::literal::hex, "AFFE" };
auto const [parse_ok, result] = convert<int32_t>(literal);
}
но это не удается с:
error: return type 'rule_definition<_, uint_parser<[...], 8, [2 * ...]>, [2 * ...]>' must match previous return type
'rule_definition<_, uint_parser<[...], 2, [2 * ...]>, [2 * ...]>' when lambda expression has unspecified explicit return type
Сообщение об ошибке ясно, но у меня нет решения для получения желаемого поведения. От диспетчеризации типа выбора динамического парсера на основе базового спецификатора зависят другие операции, поэтому этот подход полезен для моего варианта использования. Было бы особенно полезно, если бы решение также работало с реальными/двойными типами и их политиками. Я предполагаю, что это больше проблема C++ по духу.
Кстати, можно ли таким образом вернуть конкретный парсер? Требуется копия экземпляра, что может быть неэффективным, не так ли? Существуют ли другие/лучшие способы обработки обнаружения диапазона/переполнения TargetT простым сбоем синтаксического анализа?
Для удобства код также можно найти в Wandbox.
parser(base)
был бы хорош для правила синтаксического анализатора вызывающей стороны... - person Olx   schedule 29.05.2018