【问题标题】:Why does boost::spirit::qi::parse() not set this boost::variant's value?为什么 boost::spirit::qi::parse() 没有设置这个 boost::variant 的值?
【发布时间】:2011-09-28 03:32:57
【问题描述】:

当试图将文本解析为 boost::variant 时,变体的值不会改变。 解析器本身似乎工作正常,所以我的假设是我对变体代码做错了。

我正在使用 boost 1.46.1 和 以下代码在 Visual Studio 2008 中编译。

第一次更新

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>。但那又是什么呢?

第二次更新

使用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;
}

【问题讨论】:

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


    【解决方案1】:

    必须使用函数声明语法指定规则的属性:

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

    我没有尝试过,但我相信在这个改变之后它会起作用(顺便说一句,语法也是如此)。

    【讨论】:

    • 谢谢!我错过了。但是,现在它不再编译了。我更新了问题。
    • @hkaiser:是不是该在这个问题上进行常见问题解答了。也许它已经存在,但它经常出现......
    • @sehe 显然有一个常见问题解答条目(boost-spirit.com/home/articles/doc-addendum/faq/#attributes)。但也许它应该说“为什么我使用变体时我的代码不起作用?”或类似的东西。
    • @foraidt:遗憾的是,这与 Variant 无关,它适用于所有类型的属性。也许您正在寻找带有您名字的 FQA :)
    • 这已在 Spirit (Boost V1.47) 的新(即将推出)版本中进行了更新。那里使用 variant 应该可以工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多