1

以下にリストされているコードを書きました。コンパイラは、「3 つのオーバーロードのいずれも、すべての引数の型を変換できませんでした」というエラーを報告します。

MSVC 11.0 と Boost 1.51.0 を使用しています。for 式の各ブランチは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;
}
4

1 に答える 1

3

問題は、あなたの代入あいまいで、コンパイラが知らせているだけです。何が起こるか見てください:

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

これが、パーサー式の 2 番目のブランチでバリアントの初期化を曖昧にしている原因です。

幸いなことに、非常に簡単な解決策があります。型を明示的にするだけです。

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

サブルールがバリアントの明示的な型メンバーを公開するようにすることで、すべての疑いが取り除かれます (完全な一致はコンパイラにとって問題ありません)。次のようにしても、同じ効果が得られます。

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

これにより、別のサブルールが不要になりますが、IMO の読みやすさが犠牲になります。

サブルールで修正された完全な元のコードは次のとおりです。

于 2012-10-18T23:49:46.533 に答える