通过切换到更高的Boost版本1.6.1来编译错误

问题描述 投票:3回答: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中有一个从computationExprexpr的隐式转换,这是不再允许的。

我该如何修复此代码?我认为_val = construct<Acc>(_1)中的某些内容必须改变,但我缺乏这样做的技巧。

c++ boost boost-spirit boost-variant boost-proto
1个回答
3
投票

实际上,自1.62以来,recursive_wrapper更多地限制了隐式构造的选项:

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

Broken on Boost 1.62

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

在这种情况下,它很容易修复:Fixed on Boost 1.62

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

你的守则

在您的代码中,嵌套使用递归包装器会使事情变得复杂。好消息是,你不需要有两层。只需放一个:

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

实例化已经被第二个递归包装器充分地解耦。现在,一切都很好。

演示时间

请注意一些样式修复/建议:

此外,我重新排序了expr变体中的元素,因为它们在默认构造中触发无限递归。

Live On Coliru

#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)
© www.soinside.com 2019 - 2024. All rights reserved.