Ошибка при адаптации класса с BOOST_FUSION_ADAPT_ADT
У меня есть следующий класс:
#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_
Я хочу разобрать это с помощью 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_
Когда я создаю экземпляр этой грамматики (всегда следуя примеру страницы), я получаю ошибку компилятора:
typedef string::const_iterator StringIterator;
typedef Parser::MetadataParser<StringIterator> MetadataParser;
MetadataParser parser;
Я получаю много ошибок (типично для boost...), и я заметил внутри них много копий этой ошибки:
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);
Что я делаю не так? Как я могу это исправить?
РЕДАКТИРОВАТЬ
Как предложено MS, я добавил #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_
1 ответ
Хм.
После очень долгой борьбы с Modular Boost и git... Я обнаружил, что это регрессия.
Регрессия была частично исправлена этим запросом извлечения:
К сожалению, это все еще сломано в присутствии парсера перестановки. Я проверил с BOOST_FUSION_ADAPT_STRUCT
чтобы убедиться, что он не сломан каким-либо другим способом.
Я добавлю уменьшенный образец в PR для комментариев. Между тем вот репродуктор сделал самодостаточным:
#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.