Error when adapting a class with BOOST_FUSION_ADAPT_ADT
Asked Answered
L

1

4

I've the following class:

#ifndef WFRACTAL_FRACTAL_METADATA_H_
#define WFRACTAL_FRACTAL_METADATA_H_

#include <string>

namespace WFractal {
namespace Fractal {

class Metadata {

public:

    void setAuthorName(const std::string &name);
    void setAuthorEMail(const std::string &email);
    void setBriefDescription(const std::string &brief);
    void setCompleteDescription(const std::string &description);
    std::string getAuthorName() const;
    std::string getAuthorEMail() const;
    std::string getBriefDescription() const;
    std::string getCompleteDescription() const;

public:

    bool operator==(const Metadata &other);

private:

    std::string m_name;
    std::string m_email;
    std::string m_brief;
    std::string m_description;
};

} // namespace Fractal
} // namespace WFractal

#endif // !WFRACTAL_FRACTAL_METADATA_H_

I want to parse it using boost::spirit from following file content:

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

I've read from this page that I can use BOOST_FUSION_ADAPT_STRUCT in order to parse it. This is my grammar template:

#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_

When I create an instance of this grammar (always following the page example), I obtain compiler error:

typedef string::const_iterator StringIterator;
typedef Parser::MetadataParser<StringIterator> MetadataParser;
MetadataParser parser;

I obtain a lot of errors (typical of boost...) and I've noticed inside them many copy of this error:

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);

What I'm doing wrong? How can I fix it?

EDIT

As suggested by m.s. I've added the #include <boost/spirit/include/support_adapt_adt_attributes.hpp> header but this is not working.

#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_
Landy answered 1/11, 2015 at 17:10 Comment(1)
I have the same problem with Spirit X3Fluctuate
H
3

Hmm.

After very long struggle with Modular Boost and git... I've found that this is a regression.

The regression has been partially fixed by this pull request:

Sadly, it's still broken in the presence of the permutation parser. I've tested with BOOST_FUSION_ADAPT_STRUCT to verify that it is not broken in some other way.

I'll add the reduced sample to the PR for comments. Meanwhile, here's the reproducer made selfcontained:

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 you, however, change the #if 1 to #if 0, you get the output:

Parsed: (a b)

Note of course that's assuming you use a branch that has the PR 153 applied.

Hispania answered 1/11, 2015 at 23:53 Comment(5)
Added the reduced reproducer to the pr: github.com/boostorg/spirit/pull/153#issuecomment-152879056Hispania
Ok I'll wait the next release and in the meanwhile I'll use an intermediate struct in order to read data and put them in the class. the added lines are also a good idea, I'll check it. Thanks your your support.Landy
@cv_and_he Except it doesn't work! Still failing. That's the whole point of my answer. I'd just have pointed to the PR otherwise. Some more work will have to be done and I think 1.60 is already in freezeHispania
@cv_and_he Cheers. I'll delete the now - noisy commentsHispania
@NikitaKniazev yup you found one I remember. The latest related fix would have been github.com/boostorg/spirit/pull/376Hispania

© 2022 - 2024 — McMap. All rights reserved.