c++ - 提升精神QI : Auto-rule deduction on a tuple with a sequence inside an alternative function

标签 c++ boost-spirit-qi

我正在尝试使用自动规则推导来分配三个元素的元组。第二种是字符串,第三种是字符串 vector (第一个参数的类型对于这个例子来说并不重要)。

我很难理解为什么以下代码无法编译。

#include <boost/fusion/include/std_tuple.hpp>
#include <boost/spirit/include/qi.hpp>

using namespace boost::spirit::qi;
using iterator = std::string::const_iterator;

void qi_compile_test1()
{
    rule<iterator, std::string(), space_type> r_s1, r_s2;
    rule<iterator, std::vector<std::string>(), space_type> r_vec_s1, r_vec_s2;
    rule<iterator, std::tuple<float, std::string, std::vector<std::string>>(), space_type> r;

    r %=
        float_ >
        ((r_s1 > r_vec_s1) |
         (r_s2 > r_vec_s2));
}

错误如下(函数insert是在字符串上调用的,第二个参数是字符串):

/opt/wandbox/boost-1.68.0/clang-6.0.1/include/boost/spirit/home/support/container.hpp:292:15: error: no matching member function for call to 'insert'
            c.insert(c.end(), val);
            ~~^~~~~~
/opt/wandbox/boost-1.68.0/clang-6.0.1/include/boost/spirit/home/support/container.hpp:354:51: note: in instantiation of member function 'boost::spirit::traits::push_back_container<std::__1::basic_string<char>, std::__1::basic_string<char>, void>::call' requested here
        return push_back_container<Container, T>::call(c, val);

简而言之,定义了以下规则:

A > ((B > C) | (B > C))

我怀疑错误来自于 C 与 vector < B > 相同的事实,后者可以恢复为:

A > ((B > vector<B>) | (B > vector<B))

根据复合属性规则,我假设错误来自以下解析:

A > (vector<B> | vector<B>)     a : A, b: vector<A> --> (a > b): vector<A>
A > vector<B>                   a : A, b: A --> (a | b): A

由于合成属性是三个元素的元组,我希望自动规则保持三种不同类型的顺序:

A > ((B > vector<B>) | (B > vector<B))
A > (B > vector<B>)             a : A, b: A --> (a | b): A

我不明白的是,以下代码可以编译:

void qi_compile_test2()
{
    rule<iterator, int(), space_type> r_int1, r_int2;
    rule<iterator, std::vector<int>(), space_type> r_vec_int1, r_vec_int2;
    rule<iterator, std::tuple<float, int, std::vector<int>>(), space_type> r;

    r %=
        float_ >
        ((r_int1 > r_vec_int1) |
         (r_int2 > r_vec_int2));
}

唯一的区别是将类型 B 从 std::string 替换为 int。我想这会简化事情,因为 std::string 是一个容器而不是“int”类型。在这种情况下,我看不出这种变化会导致什么。

此外,通过取回第一个公式并删除元组的第一个参数,我们能够编译(仍然保持替代函数和涉及字符串的相同序列顺序)。

void qi_compile_test3()
{
    rule<iterator, std::string(), space_type> r_s1, r_s2;
    rule<iterator, std::vector<std::string>(), space_type> r_vec_s1, r_vec_s2;
    rule<iterator, std::tuple<std::string, std::vector<std::string>>(), space_type> r;

    r %=
        ((r_s1 > r_vec_s1) |
         (r_s2 > r_vec_s2));
}

我很想将等式简化为以下形式,但我认为如果不使用带有 lambda 的语义操作来展平元组,就无法实现。

void qi_compile_test4()
{
    rule<iterator, std::tuple<std::string, std::vector<std::string>>(), space_type> r_p1, r_p2;
    rule<iterator, std::tuple<float, std::string, std::vector<std::string>>(), space_type> r;

    r %=
        float_ >
        (r_p1 | r_p2 );
}

这段代码可以在这里编译: https://wandbox.org/permlink/iJLRz1TKMK2pWMVb

我在这里试图完成的是能够让元组的最后两个元素相互依赖。我想保留两个元素的顺序,但用一个替代函数分开。删除替代函数并仅保留两个语句之一进行编译,但会删除所需的逻辑。

我想避免使用语义操作,因为在我的真实案例场景中,我的元组包含更多元素(使用融合枚举的结构),因为一旦我使用语义操作在元组中分配适当的字段,我就必须分配每个元素.有人对如何解决这个问题有任何建议吗?

谢谢

最佳答案

不幸的是,Spirit(Qi 和 X3)只连接序列解析器的元组1。虽然期望解析器的平面表示似乎很自然,但 Spirit 并没有深入。它的行为非常简单2,修复将需要对属性操作进行大量重构。

  1. 然而,unaries 是透明的,所以 float_ >> lexeme[int_ >> char_]tuple<float, int, char>结果。
#include <boost/spirit/home/qi.hpp>
#include <boost/core/demangle.hpp>
#include <typeinfo>

namespace qi = boost::spirit::qi;

template <typename Iterator = char const*, typename Context = qi::unused_type, typename Parser>
void print_parser_attr_type(Parser const& p)
{
    using attr_type = typename decltype(boost::spirit::compile<qi::domain>(p))::template attribute<Context, Iterator>::type;
    std::cout << boost::core::demangle(typeid(attr_type).name()) << '\n';
}

int main()
{
    print_parser_attr_type(qi::float_ >> ((qi::int_ >> qi::char_) | (qi::int_ >> qi::char_)));
}

输出:

boost::fusion::vector<float, boost::fusion::vector<int, char> >

  1. float_ >> no_case[int_ >> char_] 可能会让您感到惊讶将完美解析为 tuple<float, tuple<int, char>>但是float_ >> (int_ >> char_)不会。

关于c++ - 提升精神QI : Auto-rule deduction on a tuple with a sequence inside an alternative function,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51833206/

相关文章:

c++ - 搜索/迭代 boost::spirit::qi::symbols

c++ - 提升灵气规则属性问题

c++ - 当我使用 boost::bind 时,为什么 boost::spirit::qi 语义操作不能使用两个参数?

c++ - boost spirit : Difference between operators "%=" and "="

c++ - 为什么 const 方法不覆盖 C++ 中的非 const 方法?

c++ - 有没有办法自动使库成为静态或动态的?

c++ - boost::spirit::qi 对输出进行重复解析

c++ - 从文件 C++ 访问对象时出现读取访问冲突。

c++ - 生成多个线程,每个线程返回多个值

c++ - getline 与 istream 和 FILE* 操作的性能差异