代码之家  ›  专栏  ›  技术社区  ›  Aleph0

切换到更高版本的Boost 1.6.1时出现编译错误

  •  3
  • Aleph0  · 技术社区  · 7 年前

    我将Boost版本从1.6.1切换到了>=1.6.2和我的 boost::spirit 解析器代码无法编译。实际上,我认为这个问题与Boost版本1.6.1到1.6.2中的bug修复有关。

    版本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

    下面是我失败代码的精简版本:

    解析器。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);
    

    解析器。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) 必须改变,但我缺乏这样做的技能。

    1 回复  |  直到 7 年前
        1
  •  3
  •   sehe    7 年前

    实际上,自1.62以来,recursive\u包装器更多地限制了隐式构造的选项:

    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::变量(<int,boost::recursive\u包装器<标准::字符串(>)&燃气轮机;x;
    x=“以前工作过”;
    标准::cout<&书信电报;boost::获取(<标准::字符串(>);(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)
    
    推荐文章