这里我尝试将字符串文字转换为数字,其中基本指定符是动态的:
#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找到代码。
答案 0 :(得分:0)
由于以下原因,您尝试执行的操作无法实现:
returning different parser types
^ C ++语言不允许。
rule
旨在作为语法的简单包装,带有附加信息(属性类型和强制属性类型标志)。通过调用rule
的赋值运算符,它将返回rule_definition
,其中包含实际语法的签名(这就是为什么存在BOOST_SPIRIT_DEFINE
的原因)。
如果您是从Qi来的X3,我会理解您的困惑。在Qi中,rule
进行了一个实际的解析器并将其存储到boost::function
中(同时丢失了任何静态信息并暗示了虚拟函数调用的成本),但是X3 rule
更接近Qi的{{3 }}。