Здесь я пытаюсь преобразовать строковый литерал в число, в котором базовый спецификатор является динамическим:
#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 .