【问题标题】:Boost::spirit processes rule with branches incorrectlyBoost::spirit 错误地处理带有分支的规则
【发布时间】:2012-10-18 15:03:09
【问题描述】:

我编写了下面列出的代码。编译器向我报告一个错误:'3 个重载都不能转换所有参数类型'。

我使用 MSVC 11.0 和 Boost 1.51.0。 m_oQueryIterationExpression 的每个表达式分支都可以正常工作,但它们不能一起工作。有什么线索吗?

#include <boost/spirit/include/qi.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/variant/recursive_variant.hpp>

namespace Ns
{
    struct Regexp     { std::string m_strEntity; };
    struct String     { std::string m_strEntity; };
    struct Identifier { std::string m_strEntity; };

    typedef int Number;

    typedef std::string Operation;
    typedef boost::variant<Regexp, Number, String, Identifier> Operand;
    typedef boost::tuple<Operation, boost::optional<std::vector<Operand> > > OperationWithOperands;

    struct QueryConcatenation;

    typedef boost::tuple<boost::recursive_wrapper<QueryConcatenation>, boost::optional<char> > typeA;
    typedef std::vector<std::vector<OperationWithOperands> > typeB;

    typedef boost::variant<typeA, typeB> QueryIteration;

    struct QueryConcatenation {
        typedef std::vector<QueryIteration> TEntity;
        TEntity m_oEntity;
    };
}

int main()
{
    using namespace Ns;
    namespace qi = boost::spirit::qi;

    qi::rule<char*, QueryConcatenation()>                                m_oQueryConcatenationExpression;
    qi::rule<char*, QueryIteration()>                                    m_oQueryIterationExpression;
    qi::rule<char*, std::vector<std::vector<OperationWithOperands> >() > m_oQueryNode;

    m_oQueryIterationExpression %= 
        qi::attr_cast<typeA, typeA>( '(' >> m_oQueryConcatenationExpression >> ')' >> -(qi::char_("*+?")) )
        | m_oQueryNode;
}

【问题讨论】:

  • 我编辑了帖子以使其不那么冗长。实际上 this is what 一个真正的 SSCCE 看起来像(24 行)
  • 还要注意您的m_oQueryNode 声明缺少qi::rule&lt;It, attr_type 的括号() , ...&gt;

标签: c++ boost boost-spirit boost-variant


【解决方案1】:

嗯,问题是,你的赋值模棱两可的,编译器只是让你知道。看看会发生什么:

typedef boost::tuple<
            boost::recursive_wrapper<STreeConstructionRuleQueryConcatenation>, 
            boost::optional<char>
        > typeA;
typedef std::vector<std::vector<STreeConstructionRuleOperationWithOperands> > typeB;

typedef boost::variant<typeA, typeB> typeAB;
typedef typeAB STreeConstructionRuleQueryIteration;

现在让我们看看一些规则中的属性兼容性:

qi::rule<Iterator, typeA(),  ascii::space_type> ruleA;
qi::rule<Iterator, typeB(),  ascii::space_type> ruleB;
qi::rule<Iterator, typeAB(), ascii::space_type> ruleAB;

// these are intended to compile, and they do:
ruleA  %= ( '(' >> m_oQueryConcatenationExpression >> ')' >> -(qi::char_("*+?")) );
ruleB  %= m_oQueryNode;
// so far, so good

// ---- Now, ideally we like the assignments to be mutually exclusive:

// This fails to assign, good! :
// ruleB  %= ( '(' >> m_oQueryConcatenationExpression >> ')' >> -(qi::char_("*+?")) );

// But HERE is the surprise:
ruleA  %= m_oQueryNode; // uhoh m_oQueryNode can be assigned to a typeA attribute as well

这就是在解析器表达式的第二个分支上使变量的初始化模棱两可的原因:它可能是任何一个!

幸运的是,有一个非常简单的解决方案:只需明确类型即可:

qi::rule<Iterator, typeAB(), ascii::space_type> ruleAB;
ruleAB %= ruleA | ruleB;

您会看到,通过使子规则公开变体的 explicit 类型成员,您消除了所有疑问(编译器可以完全匹配)。可以达到相同的效果:

ruleAB %= qi::attr_cast_type<typeA, typeA>( '(' >> m_oQueryConcatenationExpression >> ')' >> -(qi::char_("*+?")) ) | ruleB;

这消除了对另一个子规则的需要,但代价是易读性,IMO。

这是您的完整原始代码,用子规则修复:http://liveworkspace.org/code/5a7a8046b713beefba211a6a54219368(更改命名...)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多