spirit x3:本地定义的规则定义必须附加一个属性?

spirit x3: locally defined rule definition must have an attribute attached?

简单的 x3 代码无法编译,因为没有任何内容附加到第二个 ruleTest 或整个解析器。即使我们将 x3::omit[ruleTest] 放在第二个 ruleTest 周围,它仍然无法编译。

void Test(std::string const& str) {
    auto const ruleTest = x3::rule<struct _, std::string>{} =
        *(x3::char_ - ' ')[([](auto& ctx){x3::_val(ctx)+='x';})];
    x3::parse(boost::begin(str), boost::end(str), 
        ruleTest[([](auto& ctx){std::cout<<x3::_attr(ctx)<<std::endl;})] >>
        ' ' >>
        ruleTest
    );
} 

只有当我们将lambda或属性附加到x3::parse或使用BOOST_SPIRIT_DEFINE全局定义ruleTest时才能解决问题。

void Test(std::string const& str) {
    auto const ruleTest = x3::rule<struct _, std::string>{} =
        *(x3::char_ - ' ')[([](auto& ctx){x3::_val(ctx)+='x';})];
    std::string attr;
    x3::parse(boost::begin(str), boost::end(str), 
        ruleTest[([](auto& ctx){std::cout<<x3::_attr(ctx)<<std::endl;})] >>
        ' ' >>
        ruleTest, attr);
}

错误的症结似乎是

test.cpp|9 col 59| error: no match for ‘operator+=’ (operand types are ‘boost::spirit::x3::unused_type’ and ‘char’)

这是因为编译器发现绑定属性 (none) 的实际类型是 x3::unused_type,因此语义操作无法编译。

我什至不确定您希望它如何工作,因为您无法将不存在的属性中的字符更新为 'x'

这是一个提议"fix":

struct { 
    void operator()(std::string& s, char c) const { s += c; }
    void operator()(...)                    const { }
} ll;

auto const ruleTest 
    = x3::rule<struct _, std::string>{} 
    = *(x3::char_ - ' ') [([ll](auto& ctx){ ll(x3::_val(ctx), 'x');})]
    ;

看到了Live On Coliru

#include <boost/spirit/home/x3.hpp>
#include <iostream>

void Test(std::string const& str) {
    namespace x3 = boost::spirit::x3;

    struct { 
        void operator()(std::string& s, char c) const { s += c; }
        void operator()(...)                    const { }
    } ll;

    auto const ruleTest 
        = x3::rule<struct _, std::string>{} 
        = *(x3::char_ - ' ') [([ll](auto& ctx){ ll(x3::_val(ctx), 'x');})]
        ;

    //std::string attr;
    auto f = begin(str), l = end(str);
    bool ok = x3::parse(f, l, 
            ruleTest [([](auto& ctx){std::cout<<x3::_attr(ctx)<<std::endl;})] 
            >> ' ' >> ruleTest);

    if (ok)     std::cout << "Parse success\n";
    else        std::cout << "Parse failed\n";
    if (f != l) std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}

int main() {
    Test("abc def");
}