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

Boost Spirit X3:无法创建含可选列表的AST编译报错求助

问题

尝试解析一个后跟分号的可选元素列表,编写了对应的C++代码,但编译失败。使用命令g++ --std=c++17 r1.cpp -o r1编译时,报错信息显示boost::variant与std::optional<ast::pass>之间无匹配的赋值运算符。

示例代码:

#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <iostream>
#include <optional>
#include <string>
#include <vector>

namespace x3=boost::spirit::x3;

namespace ast
{
  struct doubleOrString : x3::variant<double,std::string>{
     using base_type::base_type;
     using base_type::operator=;
  };
 
  struct pass {
     std::vector<doubleOrString> dOrs;
  };
}//ast namespace

BOOST_FUSION_ADAPT_STRUCT(ast::pass,dOrs)

x3::rule<class doubleOrString_class, ast::doubleOrString> const doubleOrString = "doubleOrString";
x3::rule<class pass_class, ast::pass> const pass = "pass";
x3::rule<class es_class, std::optional<ast::pass>> const es = "es";

auto const doubleOrString_def =x3::double_ | x3::string("AString");
auto const pass_def = doubleOrString % x3::lit(",");
auto const es_def = (pass > x3::lit(";")) | x3::lit(";"));

BOOST_SPIRIT_DEFINE(doubleOrString,pass,es);

int main()
{
    using boost::spirit::x3::ascii::space;
    typedef std::string::const_iterator iterator_type;

    std::string str;
    while (getline(std::cin, str))
    {
        if (str.empty() || str[0] == 'q' || str[0] == 'Q')
            break;

        std::optional<ast::pass> esdOrs;
        iterator_type iter = str.begin();
        iterator_type const end = str.end();
        bool r = phrase_parse(iter, end, es, space, esdOrs);
        

        if (r && iter == end)
        {
            std::cout << "\nGood!\n";
        }
        else
        {
            std::cout << "-------------------------\n";
            std::cout << "Parsing failed\n";
            std::cout << "-------------------------\n";
        }
    }

    std::cout << "Bye... :-) \n\n";
    return 0;
}

编译报错信息:

usr/include/boost/spirit/home/x3/support/ast/variant.hpp:184:17: error: no match for ‘operator=’ (operand types are ‘boost::spirit::x3::variant<double, std::__cxx11::basic_string<char, std::char_traits, std::allocator<char> > >::variant_type’ {aka ‘boost::variant<double, std::__cxx11::basic_string<char, std::char_traits, std::allocator<char> > >’} and ‘std::optional<ast::pass>’)
184 |             var = std::forward<T>(rhs);
问题分析与解决

1. 语法错误:表达式多余右括号

es_def的定义末尾多了一个右括号:

auto const es_def = (pass > x3::lit(";")) | x3::lit(";"));
// 正确写法:
auto const es_def = (pass > x3::lit(";")) | x3::lit(";");

这个语法错误会导致解析器的属性推导逻辑混乱,进而触发类型不匹配的编译错误。

2. 属性类型不匹配:空分支无法填充std::optional

es规则的属性是std::optional<ast::pass>,但原定义中第二个分支x3::lit(";")没有对应的值来初始化这个optional。当匹配到单独的分号时,Spirit不知道如何将空字面量赋值给std::optional<ast::pass>,导致类型匹配失败。

修正方案:使用x3::optional简化规则

直接用x3::optional包裹pass规则,后跟分号,规则会自动处理两种情况:匹配到pass+;时生成包含pass的optional,匹配到单独;时生成空的optional,完美匹配属性类型:

auto const es_def = x3::optional[pass] > x3::lit(";");

修正后的完整代码

#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <iostream>
#include <optional>
#include <string>
#include <vector>

namespace x3=boost::spirit::x3;

namespace ast
{
  struct doubleOrString : x3::variant<double,std::string>{
     using base_type::base_type;
     using base_type::operator=;
  };
 
  struct pass {
     std::vector<doubleOrString> dOrs;
  };
}//ast namespace

BOOST_FUSION_ADAPT_STRUCT(ast::pass,dOrs)

x3::rule<class doubleOrString_class, ast::doubleOrString> const doubleOrString = "doubleOrString";
x3::rule<class pass_class, ast::pass> const pass = "pass";
x3::rule<class es_class, std::optional<ast::pass>> const es = "es";

auto const doubleOrString_def =x3::double_ | x3::string("AString");
auto const pass_def = doubleOrString % x3::lit(",");
// 修正后的es_def
auto const es_def = x3::optional[pass] > x3::lit(";");

BOOST_SPIRIT_DEFINE(doubleOrString,pass,es);

int main()
{
    using boost::spirit::x3::ascii::space;
    typedef std::string::const_iterator iterator_type;

    std::string str;
    while (getline(std::cin, str))
    {
        if (str.empty() || str[0] == 'q' || str[0] == 'Q')
            break;

        std::optional<ast::pass> esdOrs;
        iterator_type iter = str.begin();
        iterator_type const end = str.end();
        bool r = phrase_parse(iter, end, es, space, esdOrs);
        

        if (r && iter == end)
        {
            std::cout << "\nGood!\n";
            // 可选:打印解析结果
            if (esdOrs) {
                std::cout << "Parsed " << esdOrs->dOrs.size() << " elements\n";
            } else {
                std::cout << "No elements parsed\n";
            }
        }
        else
        {
            std::cout << "-------------------------\n";
            std::cout << "Parsing failed\n";
            std::cout << "-------------------------\n";
        }
    }

    std::cout << "Bye... :-) \n\n";
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 15:20:52