boost::spirit::qi

4
考虑以下代码:(Boost.Spirit 2.5.1)
qi::parse(str.begin(), str.end(), (+qi::alpha)[[](const string& s){cout << s<< '\n';}]
                                    >> (*(qi::char_(',') | qi::char_('\'')))
                                    >> qi::uint_[[](int integer){cout << integer << '\n';}]);
< p > [[](int integer){cout << integer << '\n';}] 这段代码可以正常工作,但是对于+qi::alpha的类似代码则不行。

如何修改这段代码呢?


关于它,哪些方面“不能工作”?你遇到了什么错误?还是根本没有打印任何内容? - Nicol Bolas
我不确定是否应该发布非常长的错误行。 - user5262
@user5262:我绝对肯定你必须这么做。 - sehe
2个回答

6

Boost Spirit尚不支持C++0x/C++11的lambda表达式1 编辑 显然,支持已经改进(我今天早些时候使用了一个较旧的Boost版本进行了测试)。现在,使用Boost 1_48和g++ 4.6.1,以下内容似乎可以正常工作。耶!

qi::as_string[]

我认为您会想要了解 qi::as_string,以获取暴露的属性作为std :: string,而不是默认的std :: vector<CharT>

    qi::parse(str.begin(), str.end(),
        qi::as_string [ +qi::alpha ] 
        [
            [](const std::string&){std::cout << s << '\n';}
        ]
        >> (*(qi::char_(',') | qi::char_('\'')))
        >> qi::uint_
        [
            [](int integer){std::cout << integer << '\n';}
        ]);

但在我看来,它的语法并不是很友好。相反,我更喜欢phoenixV2:

    qi::parse(str.begin(), str.end(),
        qi::as_string [ +qi::alpha ] [ std::cout << _1 << '\n' ]
        >> (*(qi::char_(',') | qi::char_('\'')))
        >> qi::uint_ [ std::cout << _1 << '\n' ]);

这已经是一个更短、更简洁的语法了。请参考以下内容: 下面是一个有些牵强的例子,展示了其中一些功能,并直接将属性引用传递到parse函数中:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <algorithm>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;

bool reverse(std::string& value)
{
    std::reverse(value.begin(), value.end());
    return true; // false makes the parsing fail
}

int main()
{
    std::string str("sometext,123");

    auto f(str.begin()), l(str.end());

    std::string s;
    unsigned int i;

    qi::parse(f,l,
            qi::as_string [ +qi::alpha ] [ reverse ]
            >> qi::omit [ *qi::char_(",\'") ]
            >> qi::uint_,

            s, i);

    std::cout << s << std::endl;
    std::cout << i << std::endl;
}

输出:

txetemos
123

1 PhoenixV3在1_48版本中可能会对此提供一些支持(我没有检查过); 你需要

 #define BOOST_RESULT_OF_USE_DECLTYPE
 #define BOOST_SPIRIT_USE_PHOENIX_V3

请参考http://boost.2283326.n4.nabble.com/Boost-Spirit-Phoenix-V3-An-Overview-td3583792.html的介绍。

Lambda表达式显然可以正常工作,因为OP的'int' lambda函数可以正常工作。正如Cubbi所指出的那样,问题在于+qi::alpha的合成属性是std::vector<char>而不是std::string。对于非终端符号,它们之间的转换是隐式完成的,但对于语义动作则不是。 - ildjarn
@ildjarn:你说得对,事情已经改变了。我已经更新了我的回答。我确实了解到了这种转换,我认为使用qi::as_string的建议也很有价值。至于那个关于额外lambda参数信息的线程链接,我已经在另一条评论中提供了,现在我可以忘记它了,至少在gcc上是这样的:) - sehe
我同意,“qi::as_string” + 一元lambda是一个简洁的解决方案。对你的编辑点赞。:-] - ildjarn

5
你的代码给我带来了以下编译器错误,跳过了一些部分。
/usr/include/boost/spirit/home/support/action_dispatch.hpp:142:13:
error: no matching function for call to
‘action_dispatch<>::do_call(
    const main()::<lambda(const string&)>&,
    action_dispatch<>::fwd_tag<std::vector<char>>,
...

简而言之,传给你的lambda函数的参数是vector<char>,而不是string

因此,将string替换为vector<char>

(+qi::alpha)[[](const std::vector<char>& s) {
      cout << std::string(s.begin(), s.end()) << '\n';
}]

1
为什么是-1?它可以在g++ 4.6.2 / boost 1.47.0下编译和运行。 - Cubbi
1
令我惊讶的是,这似乎是一个正确的答案。但是,qi::as_string []和/或Phoenix是更自然和习惯的解决方案。FWIW,我基于现成的知识回答了问题(请参见Hartmut Kaiser在Spirit-general列表回复以及Joel de Guzman的跟进评论:Without phoenix, you are on your own to extract all that information from the context. Fiddly!)。 - sehe
@sehe 的确,to_string 更好。我主要是发帖展示如何处理“非常长的错误行”。 - Cubbi
@Cubbi:非常好的观点。让我为你点赞 :) 这实际上是我有时在用户列表中做的事情(例如,指出Spirit库中语法无法编译的各个点处的解释性注释;通常它们会拼写出问题所在)。 - sehe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接