Ошибка компиляции при переходе на более высокую версию Boost 1.6.1

Я переключил свою версию Boost с 1.6.1 на> = 1.6.2 и мой boost::spirit Код парсера не компилируется. На самом деле, я думаю, что проблема связана с исправлением ошибки в Boost Variant с версии 1.6.1 до версии 1.6.2.

Примечания к выпуску версии 1.6.2 гласят:

Variant constructors and assignment operators now do not participate in overload resolutions if variant can not hold the input type #5871, #11602

Вот урезанная версия моего ошибочного кода:

parser.h

#pragma once
#include <string>
#include <boost/variant.hpp>

struct AccTag {};

template <typename tag> struct unop;

typedef unop<AccTag> Acc;

typedef boost::variant<
boost::recursive_wrapper<Acc>
> computationExpr;

typedef boost::variant<
boost::recursive_wrapper<computationExpr>,
int
> expr;

template <typename tag> struct unop
{
unop() : oper1() {
}
explicit unop(const expr& o) : oper1(o) { }
expr oper1;
};

expr parse(const std::string& expression, bool& ok);

Parser.cpp

#include "Parser.h"
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>

using namespace boost;

template <typename Iterator = std::string::iterator, typename Skipper = spirit::qi::space_type>
class ParserImpl : public spirit::qi::grammar<Iterator, expr(), Skipper>
{
public:

ParserImpl() : ParserImpl::base_type(expr_)
{
using namespace boost::spirit::qi;
using namespace boost::phoenix;

expr_          = props_.alias();

props_ = (
(lit("Acc") >> "(" >> int_ >> ")")[_val = construct<Acc>(_1) /* Most likely the source of the error */]
);

}

spirit::qi::rule<Iterator, expr(), Skipper> props_;
spirit::qi::rule<Iterator, expr(), Skipper> expr_;
};expr parse(const std::string& expression, bool& ok)
{
expr result;
std::string formula = expression;
ParserImpl<> parser;
auto b = formula.begin();
auto e = formula.end();
ok = spirit::qi::phrase_parse(b, e, parser, spirit::qi::space, result);
if (b != e) {
ok = false;
}
return result;

}

Код компилируется без проблем в версии 1.6.1, но завершается с ошибкой в ​​версии 1.6.2 с ошибкой:

.../proto/transform/default.hpp(154): error C2679: Binary operator "=": ...

Я думаю, в версии 1.6.1 было неявное преобразование из computationExpr в expr, который больше не допускается.

Как я могу исправить этот код? Я думаю что-то в _val = construct<Acc>(_1) Должен быть изменен, но мне не хватает навыков, чтобы сделать это.

3

Решение

Действительно, recursive_wrapper ограничивает опции для неявного конструирования больше, чем с 1.62:

Wandbox on Boost 1.61

boost::variant<int, boost::recursive_wrapper<std::string> > x;
x = "worked before";
std::cout << boost::get<std::string>(x) << "\n";

Сломан на Boost 1.62

boost::variant<int, boost::recursive_wrapper<std::string> > x;
x = "worked before";
std::cout << boost::get<std::string>(x) << "\n";

В этом случае это легко исправить: Исправлено в Boost 1.62

x = std::string("Hello world");

Ваш код

В вашем коде вложенное использование рекурсивных оболочек усложняет ситуацию. Хорошая новость в том, что вам не нужно иметь два слоя. Просто бросьте одну:

typedef boost::variant<
int,
computationExpr
> expr;

Инстанцирование уже достаточно отделено второй рекурсивной оболочкой. Теперь все снова хорошо.

Демо Время

Обратите внимание на некоторые исправления стиля / предложения:

Кроме того, я переупорядочил элементы в expr вариант, потому что они вызывали бесконечную рекурсию при построении по умолчанию.

Жить на Колиру

#pragma once
#include <string>
#include <boost/variant.hpp>

struct AccTag {};

template <typename> struct unop;
typedef unop<AccTag> Acc;

typedef boost::variant<
boost::recursive_wrapper<Acc>
> computationExpr;

typedef boost::variant<
int,
computationExpr
> expr;

template <typename> struct unop {
unop() : oper1() { }
explicit unop(const expr& o) : oper1(o) { }
expr oper1;
};

expr parse(const std::string& expression, bool& ok);
#include "Parser.h"
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>

namespace qi = boost::spirit::qi;

template <typename Iterator = std::string::const_iterator, typename Skipper = qi::space_type>
class ParserImpl : public qi::grammar<Iterator, expr(), Skipper>
{
public:

ParserImpl() : ParserImpl::base_type(expr_)
{
namespace phx = boost::phoenix;
using namespace qi;

expr_  = props_.alias();

props_ =
(lit("Acc") >> '(' >> int_ >> ')')[_val = phx::construct<Acc>(_1)]
;
}

private:
qi::rule<Iterator, expr(), Skipper> props_;
qi::rule<Iterator, expr(), Skipper> expr_;
};

expr parse(const std::string& formula, bool& ok)
{
expr result;
ParserImpl<> parser;
auto b = formula.begin();
auto e = formula.end();
ok = qi::phrase_parse(b, e, parser >> qi::eoi, qi::space, result);
return result;

}
static inline std::ostream& operator<<(std::ostream& os, Acc const& o) {
return os << "Acc(" << o.oper1 << ")";
}

int main() {
bool ok;
auto e = parse("Acc (3)", ok);

if (ok)
std::cout << "Parsed: " << e << "\n";
else
std::cout << "Parse failed\n";
}

Печать

Parsed: Acc(3)
3

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector