C++ Boost spirit x3:复合属性编译时错误(枚举类)

C++ Boost spirit x3:复合属性编译时错误(枚举类),c++,boost,boost-spirit,boost-spirit-x3,C++,Boost,Boost Spirit,Boost Spirit X3,我最近正在使用boost spirit x3编写一个最简单的解析器。它包含两条规则:标识符和单个字符运算符。当然,我使用符号表实现了操作符,它生成了一个操作符类型枚举类标识符解析为std::strings。但是,当将标识符和运算符组合到单个解析器中时,代码拒绝编译(请参阅问题末尾的代码段) 请注意,如果使用整数更改运算符类型enum,则一切正常。运算符和标识符分离时也能很好地解析 模板错误消息太大,无法附加,太模糊,我无法理解,但我怀疑它与std::variant的构造/移动语义有关。但是,en

我最近正在使用boost spirit x3编写一个最简单的解析器。它包含两条规则:标识符和单个字符运算符。当然,我使用符号表实现了操作符,它生成了一个操作符类型
枚举类
标识符解析为
std::string
s。但是,当将标识符和运算符组合到单个解析器中时,代码拒绝编译(请参阅问题末尾的代码段)

请注意,如果使用整数更改运算符类型enum,则一切正常。运算符和标识符分离时也能很好地解析

模板错误消息太大,无法附加,太模糊,我无法理解,但我怀疑它与
std::variant
的构造/移动语义有关。但是,
enum类
不应该与普通的
int
有很大的不同。它是否与枚举类的默认构造函数有关?如何绕过这一点

这是密码

#包括
#包括
#包括
名称空间x3=boost::spirit::x3;
自动添加字符=[](自动上下文(&C){
x3::_val(上下文)。向后推(x3:_attr(上下文));
};
x3::规则标识符{“标识符”};
常量自动标识符_def=x3::lexeme[x3::char_uz(“a-zA-Z”)[addCharacter]>*(x3::char_uz(“a-zA-Z0-9”)[addCharacter]);
提升精神定义(标识符);
枚举类操作类型
{
加上,
减
};
结构操作:x3::符号
{
操作工()
{
添加(“+”,OperType::plus)(“-”,OperType::减号);
}
}歌剧;
x3::规则运算符{“运算符”};
const auto oper_def=x3::lexeme[opers_];
提升精神定义(oper);
int main()
{
字符串输入{“iden1+-iden2”};
std::向量标记;
自动启动=input.cbegin();
自动结果=x3::短语解析(start,input.cend(),(+(标识符| oper)),x3::空格,令牌);
返回0;
}

编写复合解析器时是否存在陷阱?我错过了什么?谢谢您的时间。

std::variant
还不支持属性兼容性

更改为
boost::variant
将使其可编译:

或者,如果您需要std::variant,以下是使其实际工作的方法:


代码也少了20行:非常感谢您对我们不断的帮助!spirit x3文档中似乎没有提到这个细节,或者我无意中遗漏了它。
#include <boost/spirit/home/x3.hpp>
#include <variant>
#include <fmt/ranges.h>
#include <fmt/ostream.h>

namespace x3 = boost::spirit::x3;

auto addCharacter = [](auto& context) {
    x3::_val(context).push_back(x3::_attr(context));
};

x3::rule<class IdentifierTag, std::string> identifier{"identifier"};
const auto identifier_def =
    x3::lexeme[x3::char_("a-zA-Z")[addCharacter] >> *(x3::char_("a-zA-Z0-9")[addCharacter])];

BOOST_SPIRIT_DEFINE(identifier)

enum class OperType
{
    plus,
    minus
};

static inline std::ostream& operator<<(std::ostream& os, OperType ot) {
    switch(ot) {
        case OperType::plus: return os << "plus";
        case OperType::minus: return os << "minus";
    }
    return os << "?";
}

struct Opers_ : x3::symbols<OperType>
{
    Opers_()
    {
        add("+", OperType::plus)
           ("-", OperType::minus);
    }
} opers_;

x3::rule<class OperTypeTag, OperType> oper{"operator"};
const auto oper_def = x3::lexeme[opers_];

BOOST_SPIRIT_DEFINE(oper)

int main() {
    std::string const input{"iden1 + - iden2"};

    std::vector<boost::variant<std::string, OperType>> tokens;

    auto f = input.begin(), l = input.end();
    auto result = x3::phrase_parse(
            f, l,
            +(identifier | oper),
            x3::space,
            tokens);

    if (result) {
        fmt::print("Parsed: {}\n", tokens);
    } else {
        fmt::print("Parse failed\n");
    }

    if (f!=l) {
        fmt::print("Remaining: '{}'\n", std::string(f,l));
    }
}
Parsed: {iden1, plus, minus, iden2}