Почему boost :: spirit :: qi :: parse () не устанавливает это значение boost :: option? - PullRequest
5 голосов
/ 04 июля 2011

При попытке разобрать текст в boost :: option, значение варианта не изменяется. Сами парсеры, кажется, работают нормально, поэтому я предполагаю, что я делаю что-то не так с кодом варианта.

Я использую boost 1.46.1 и , следующий код компилируется в Visual Studio 2008.

1-е обновление

hkaiser отметил, что аргументы шаблона правила и грамматики должны быть не Variant, а Variant().
Это немного "дальше", так как теперь у меня ошибка компиляции в boost_1_46_1\boost\variant\variant.hpp(1304). Комментарий гласит:

// NOTE TO USER :
// Compile error here indicates that the given type is not 
// unambiguously convertible to one of the variant's types
// (or that no conversion exists).

Так что, очевидно, атрибут выражения (qi::double_ | +qi::char_) не boost::variant<double, std::string>. Но что тогда?

2-е обновление

Использование typedef boost::variant<double, std::vector<char>> Variant; работает для парсера. Однако это не так просто использовать, как std :: string ...

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

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

    typedef std::string::const_iterator Iterator;

    const std::string a("foo"), b("0.5");

    // This works
    {
        std::string stringResult;
        Iterator itA = a.begin();
        const bool isStringParsed =
            qi::parse(itA, a.end(), +qi::char_, stringResult);

        double doubleResult = -1;
        Iterator itB = b.begin();
        const bool isDoubleParsed =
            qi::parse(itB, b.end(), qi::double_, doubleResult);

        std::cout
                << "A Parsed? " << isStringParsed <<
                ", Value? " << stringResult << "\n"
                << "B Parsed? " << isDoubleParsed <<
                ", Value? " << doubleResult << std::endl;

        // Output:
        // A Parsed? 1, Value? foo
        // B Parsed? 1, Value? 0.5
    }


    // This also works now
    {
        typedef boost::variant<double, std::vector<char>> Variant; // vector<char>, not string!

        struct variant_grammar : qi::grammar<Iterator, Variant()> // "Variant()", not "Variant"!
        {
            qi::rule<Iterator, Variant()> m_rule; // "Variant()", not "Variant"!

            variant_grammar() : variant_grammar::base_type(m_rule)
            {
                m_rule %= (qi::double_ | +qi::char_);
            }
        };

        variant_grammar varGrammar;

        Variant varA(-1), varB(-1);
        Iterator itA = a.begin();
        const bool isVarAParsed = qi::parse(itA, a.end(), varGrammar, varA);
        Iterator itB = b.begin();
        const bool isVarBParsed = qi::parse(itB, b.end(), varGrammar, varB);

        // std::vector<char> cannot be put into std::cout but
        // needs to be converted to a std::string (or char*) first.
        // The conversion I came up with is very ugly but it's not the point
        // of this question anyway, so I omitted it.
        // You'll have to believe me here, when I'm saying it works..

        // Output:
        // A (variant): Parsed? 1, Value? foo, Remaining text = ''
        // B (variant): Parsed? 1, Value? 0.5, Remaining text = ''
    }

    return 0;
}

1 Ответ

4 голосов
/ 04 июля 2011

Атрибут правила должен быть указан с использованием синтаксиса объявления функции:

qi::rule<Iterator, Variant()> m_rule;

Я не пробовал, но я полагаю, что это сработает после этого изменения (то же самое требуется для грамматики, кстати).

...