You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Boost Spirit X3解析带重载构造函数的结构体?

解决Boost Spirit X3解析重载构造函数结构体的类型匹配问题

问题根源

直接使用x3::int_ | (x3::int_ >> x3::lit("-") >> x3::int_)组合规则会编译失败,核心原因有两点:

  1. 属性类型不匹配:x3::int_解析返回size_t类型,而规则目标类型是MyRange,两者无法自动转换。
  2. 规则顺序错误:若先匹配单值规则,范围格式(如1-2)会被提前匹配为单值1,剩余的-2无法解析,导致逻辑错误。

解决方案

方案1:使用语义动作转换类型(推荐)

通过语义动作将单值解析结果转换为MyRange对象,同时调整规则顺序优先匹配范围格式:

#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/home/x3.hpp>
#include <iostream>
namespace x3 = boost::spirit::x3;

struct MyRange
{
    size_t start;
    size_t end;
    explicit MyRange(size_t start, size_t end = 0) 
        : start(start), end(end == 0 ? start : end)
    {
    }
};

BOOST_FUSION_ADAPT_STRUCT(MyRange, start, end)

int main()
{
    // 优先匹配范围格式,再匹配单值格式,单值通过语义动作构造MyRange
    auto range_constraint = x3::rule<struct test_struct, MyRange>{} 
        = (x3::int_ >> x3::lit("-") >> x3::int_) 
        | x3::int_[([](auto& ctx) {
            _val(ctx) = MyRange(_attr(ctx));
        })];

    for (std::string input : {"1-2", "1", "1-", "garbage"})
    {
        MyRange result{0};
        auto iter = input.begin();
        // 解析并传入结果对象
        auto success = x3::phrase_parse(iter, input.end(),
                                        range_constraint,
                                        x3::ascii::space,
                                        result);
        // 确保输入被完全解析(避免部分匹配)
        success &= (iter == input.end());

        std::cout << "`" << input << "` -> " << std::boolalpha << success;
        if (success) {
            std::cout << " (start: " << result.start << ", end: " << result.end << ")";
        }
        std::cout << std::endl;
    }
    return 0;
}

方案2:全局类型转换特化

通过特化x3::transform_attribute让Spirit自动完成size_t到MyRange的转换,无需语义动作:

#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/home/x3.hpp>
#include <iostream>
namespace x3 = boost::spirit::x3;

struct MyRange
{
    size_t start;
    size_t end;
    explicit MyRange(size_t start, size_t end = 0) 
        : start(start), end(end == 0 ? start : end)
    {
    }
};

BOOST_FUSION_ADAPT_STRUCT(MyRange, start, end)

// 特化类型转换规则
namespace x3 {
    template<>
    struct transform_attribute<MyRange, size_t, void> {
        static MyRange pre(size_t s) {
            return MyRange(s);
        }
    };
}

int main()
{
    auto range_constraint = x3::rule<struct test_struct, MyRange>{} 
        = (x3::int_ >> x3::lit("-") >> x3::int_) | x3::int_;

    for (std::string input : {"1-2", "1", "1-", "garbage"})
    {
        MyRange result{0};
        auto iter = input.begin();
        auto success = x3::phrase_parse(iter, input.end(),
                                        range_constraint,
                                        x3::ascii::space,
                                        result);
        success &= (iter == input.end());

        std::cout << "`" << input << "` -> " << std::boolalpha << success;
        if (success) {
            std::cout << " (start: " << result.start << ", end: " << result.end << ")";
        }
        std::cout << std::endl;
    }
    return 0;
}

关键修改说明

  1. 规则顺序调整:先匹配start-end格式,避免单值规则提前截取范围的前缀。
  2. 类型转换:方案1通过局部语义动作构造MyRange,不会影响其他解析逻辑;方案2通过全局特化实现自动转换,适合全局需要该转换的场景。
  3. 完全解析检查:添加iter == input.end()判断,确保输入字符串被完整解析,避免"1-garbage"这类部分匹配的错误判定。

内容的提问来源于stack exchange,提问作者Mikhail

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 20:05:13