C++ Spirit.X3,lambda返回不同的解析器类型

C++ Spirit.X3,lambda返回不同的解析器类型,c++,boost-spirit-x3,C++,Boost Spirit X3,在这里,我尝试将字符串文字转换为数字,其中基本说明符是动态的: #include <string> #include <boost/spirit/home/x3.hpp> namespace ast { struct literal { enum base_specifier { bin, oct, hex }; base_specifier base; std::string literal;

在这里,我尝试将字符串文字转换为数字,其中基本说明符是动态的:

#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);
}
#包括
#包括
名称空间ast{
结构文字{
枚举基_说明符{bin,oct,hex};
base_说明符base;
字符串文本;
};
}
名称空间x3=boost::spirit::x3;
模板
自动as=[](自动p){返回x3::规则{}=x3::as_解析器(p);};
模板
std::pair convert(ast::literal const&node)
{
auto const parse=[](ast::literal::base_说明符base,auto const&literal){
使用base_说明符=ast::literal::base_说明符;
auto const parser=[](base_说明符base){
开关(底座){
案例库_说明符::bin:{
使用parser\u type=x3::uint\u解析器;
parser_type const p=parser_type{};
返回为(p);
}
基于事例的说明符::oct:{
使用parser\u type=x3::uint\u解析器;
parser_type const p=parser_type{};
返回为(p);
}
case base_说明符::十六进制:{
使用parser\u type=x3::uint\u解析器;
parser_type const p=parser_type{};
返回为(p);
}
违约:
中止();
}
};
自动iter=std::begin(文字);
auto const end=std::cend(文字);
塔吉特属性;
boolparse_ok=x3::parse(iter,end,parser(base),attribute);
返回std::make_tuple(parse_ok&&(iter==end),属性);
};
//这里还有其他复杂的东西
返回parse(node.base、node.literal);
}
int main()
{
ast::literal literal{ast::literal::hex,“AFFE”};
自动常量[parse_ok,result]=转换(文本);
}
但它在以下方面失败了:

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
错误:返回类型“规则定义”必须与以前的返回类型匹配
lambda表达式具有未指定的显式返回类型时的“rule_definition”
错误信息很清楚,但我没有获得所需行为的解决方案。基于基本说明符的动态解析器选择类型分派依赖于其他操作,因此这些方法对于我的用例非常有用。如果该解决方案也适用于real/double类型及其策略,那么它将特别有用。我认为,它是一个C++的问题,就像灵魂一样。 顺便说一句,以这种方式返回特定的解析器是否节省?它需要一个实例的副本,这可能是无效的,不是吗?是否有其他/更好的方法通过简单的解析失败来处理TargetT的范围/溢出检测


为方便起见,代码也可以在中找到。

您试图执行的设计是不可能的,因为:

returning different parser types

^:C++语言不允许这样做。


规则
是一个简单的语法包装器,包含额外的信息(属性类型和强制属性类型标志)。通过调用
规则
的赋值运算符,它将返回
规则定义
,其中包含实际语法的签名(这就是为什么有
BOOST\u-SPIRIT\u-DEFINE


如果你是从齐来的X3,我理解你的困惑。在Qi中,rule生成一个实际的解析器,并将其存储到一个
boost::function
(同时丢失任何静态信息并意味着虚拟函数调用的成本),但X3
rule
更接近Qi。

经过一段时间后,我得出结论,没有简单的方法。一种可能是使用变体,甚至不返回解析器。只需调用x3::parse并返回结果(带/不带要访问的变量)。即使嵌入语法
parser(base)
对于调用方解析器规则来说也很酷……也许你可以在回答中提到
x3::any_parser
,这是询问者需要的。@llonesmiz这是一个很好的“黑客”!请把它贴出来作为问题的答案。