使用BOOST_FUSION_ADAPT_ADT调整类时出错

时间:2015-11-01 17:10:56

标签: c++ boost grammar boost-spirit

我有以下课程:

metadata {
  author = "Me";
  email = "myemail";
  brief = "brief description";
  description = "complete description";
}

我想使用以下文件内容中的BOOST_FUSION_ADAPT_STRUCT来解析它:

#ifndef WFRACTAL_FRACTAL_PARSER_METADATAGRAMMAR_H_
#define WFRACTAL_FRACTAL_PARSER_METADATAGRAMMAR_H_

#include <boost/fusion/adapted/adt/adapt_adt.hpp>
#include <boost/fusion/include/adapt_adt.hpp>
#include <boost/spirit/include/qi_no_case.hpp>
#include <string>
#include "Fractal/Metadata.h"

BOOST_FUSION_ADAPT_ADT(
    WFractal::Fractal::Metadata,
    (obj.getAuthorName(), obj.setAuthorName(val))
    (obj.getAuthorEMail(), obj.setBriefDescription(val))
    (obj.getBriefDescription(), obj.setCompleteDescription(val))
    (obj.getCompleteDescription(), obj.setAuthorEMail(val))
)

namespace WFractal {
namespace Fractal {
namespace Parser {

template <typename Iterator>
struct MetadataParser : boost::spirit::qi::grammar<Iterator, Metadata(), boost::spirit::ascii::space_type> {
    MetadataParser() : MetadataParser::base_type(start) {
        using boost::spirit::qi::int_;
        using boost::spirit::qi::lit;
        using boost::spirit::qi::double_;
        using boost::spirit::qi::lexeme;
        using boost::spirit::ascii::char_;
        using boost::spirit::ascii::no_case;

        quoted_string %= lexeme['"' >> +(char_ - '"') >> '"'];

        start %=
        no_case[lit("metadata")]
        >> '{'
        >>  no_case[lit("author")] >> '=' >> quoted_string >> ';'
        >>  no_case[lit("email")] >> '=' >> quoted_string >> ';'
        >>  no_case[lit("brief")] >> '=' >> quoted_string >> ';'
        >>  no_case[lit("description")] >> '=' >> quoted_string >> ';'
        >>  '}'
        ;
    }

    boost::spirit::qi::rule<Iterator, std::string(), boost::spirit::ascii::space_type> quoted_string;
    boost::spirit::qi::rule<Iterator, Metadata(), boost::spirit::ascii::space_type> start;
};

} // namespace Parser
} // namespace Fractal
} // namespace WFractal

#endif // !WFRACTAL_FRACTAL_PARSER_METADATAGRAMMAR_H_

我已经从this page读到我可以使用typedef string::const_iterator StringIterator; typedef Parser::MetadataParser<StringIterator> MetadataParser; MetadataParser parser; 来解析它。这是我的语法模板:

src/Fractal/FileFactory.cpp:27:17:   required from here
/usr/include/boost/spirit/home/qi/detail/assign_to.hpp:152:18: error: no matching function for call to ‘boost::fusion::extension::adt_attribute_proxy<WFractal::Fractal::Metadata, 0, false>::adt_attribute_proxy(const std::__cxx11::basic_string<char>&)’
             attr = static_cast<Attribute>(val);

当我创建这个语法的实例时(总是遵循页面示例),我得到编译器错误:

#include <boost/spirit/include/support_adapt_adt_attributes.hpp>

我获得了很多错误(典型的提升......)我已经注​​意到了这个错误的许多副本:

#ifndef WFRACTAL_FRACTAL_PARSER_METADATAPARSER_H_
#define WFRACTAL_FRACTAL_PARSER_METADATAPARSER_H_

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/fusion/adapted/adt/adapt_adt.hpp>
#include <boost/fusion/include/adapt_adt.hpp>
#include <boost/spirit/include/support_adapt_adt_attributes.hpp>
#include <string>
#include "Fractal/Metadata.h"

BOOST_FUSION_ADAPT_ADT(
    WFractal::Fractal::Metadata,
    (obj.getAuthorName(), obj.setAuthorName(val))
    (obj.getAuthorEMail(), obj.setAuthorEMail(val))
    (obj.getBriefDescription(), obj.setBriefDescription(val))
    (obj.getCompleteDescription(), obj.setCompleteDescription(val))
)

namespace WFractal {
namespace Fractal {
namespace Parser {

template <typename Iterator>
struct MetadataParser : boost::spirit::qi::grammar<Iterator, Metadata(), boost::spirit::ascii::space_type> {
    MetadataParser() : MetadataParser::base_type(start) {
        using boost::spirit::qi::lit;
        using boost::spirit::qi::lexeme;
        using boost::spirit::ascii::char_;
        using boost::spirit::ascii::no_case;

        quoted_string %= lexeme['"' >> +(char_ - '"') >> '"'];

        start %=
        no_case[lit("metadata")]
        >> '{'
        >> ((no_case[lit("author")] >> '=' >> quoted_string >> ';')
        ^  (no_case[lit("email")] >> '=' >> quoted_string >> ';')
        ^  (no_case[lit("brief")] >> '=' >> quoted_string >> ';')
        ^  (no_case[lit("description")] >> '=' >> quoted_string >> ';'))
        >>  '}'
        ;
    }

    boost::spirit::qi::rule<Iterator, std::string(), boost::spirit::ascii::space_type> quoted_string;
    boost::spirit::qi::rule<Iterator, Metadata(), boost::spirit::ascii::space_type> start;
};

} // namespace Parser
} // namespace Fractal
} // namespace WFractal

#endif // !WFRACTAL_FRACTAL_PARSER_METADATAPARSER_H_

我做错了什么?我该如何解决?

修改

按照m.s.的建议我添加了{{1}}标题,但这不起作用。

{{1}}

1 个答案:

答案 0 :(得分:3)

嗯。

经过与Modular Boost和git的长期斗争......我发现这是一个倒退。

此拉动请求部分修复了回归:

可悲的是,在置换解析器的存在下,它仍然被打破了。我已经使用BOOST_FUSION_ADAPT_STRUCT进行了测试,以确认它没有以其他方式破坏。

我将减少的样本添加到PR进行评论。与此同时,这里的复制者是自包含的:

<强> Live On Coliru

#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted.hpp>
#include <iostream>

class Foo {
  public:
    char const& getA() const { return a; } 
    char const& getB() const { return b; } 

    void setA(char value)    { a = value; } 
    void setB(char value)    { b = value; } 
  private:
    char a, b;
};

BOOST_FUSION_ADAPT_ADT(
        Foo,
        (char const&, char const&, obj.getA(), obj.setA(val))
        (char const&, char const&, obj.getB(), obj.setB(val))
    )


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

    boost::spirit::istream_iterator f(std::cin), l; // input e.g. "a=a;b=b;"
    Foo foo;

    bool r = qi::parse(f, l,
#if 0 // FAILS TO COMPILE
                      ("a=" >> qi::char_ >> ';')
                    ^ ("b=" >> qi::char_ >> ';')
#else // COMPILES WITH FIX FROM PR #153
                      ("a=" >> qi::char_ >> ';')
                   >> ("b=" >> qi::char_ >> ';')
#endif 
                , foo);

    if (r)
        std::cout << "Parsed: " << boost::fusion::as_vector(foo) << "\n";
    else
        std::cerr << "Parse failed\n";
}

但是,如果您将#if 1更改为#if 0,则会获得输出:

Parsed: (a b)
  

注意当然假设您使用的是已应用PR 153的分支。