Boost logo

Boost :

Subject: [boost] [proto][variant] variant crashes proto expression
From: Igor R (boost.lists_at_[hidden])
Date: 2016-05-12 15:10:47

The following code is a slightly modified Proto calc2 example. Instead
of doubles I use variant<int, double>, and the expression is just _1 =
This code triggers assertion in variant/detail/forced_return.hpp, so
it looks like some variant instance gets messed up. It happens when
the value returned from proto::eval(*this, ctx) is being copied.
It can be reproduced both with MSVC and gcc, with Boost 1.60.

Is there any workaround for this issue?


#include <iostream>
#include <boost/proto/proto_typeof.hpp>
#include <boost/proto/core.hpp>
#include <boost/proto/context.hpp>
#include <boost/variant.hpp>

namespace proto = boost::proto;
using proto::_;

typedef boost::variant<int, double> var_t;

template<typename Expr>
struct calculator_expression;

// Tell proto how to generate expressions in the calculator_domain
struct calculator_domain
  : proto::domain<proto::generator<calculator_expression> >

// Will be used to define the placeholders _1 and _2
template<int I> struct placeholder {};

// Define a calculator context, for evaluating arithmetic expressions
// (This is as before, in calc1.cpp)
struct calculator_context
  : proto::callable_context< calculator_context const >
    // The values bound to the placeholders
    var_t d[2];

    // The result of evaluating arithmetic expressions
    typedef var_t result_type;

    explicit calculator_context(const var_t &d1 = var_t(), const var_t
&d2 = var_t())
        d[0] = d1;
        d[1] = d2;

    // Handle the evaluation of the placeholder terminals
    template<int I>
    result_type operator ()(proto::tag::terminal, placeholder<I>) const
        return d[ I - 1 ];

// Wrap all calculator expressions in this type, which defines
// operator () to evaluate the expression.
template<typename Expr>
struct calculator_expression
  : proto::extends<Expr, calculator_expression<Expr>, calculator_domain>
    explicit calculator_expression(Expr const &expr = Expr())
      : calculator_expression::proto_extends(expr)


    // Override operator () to evaluate the expression
    var_t operator ()() const
        calculator_context const ctx;
        return proto::eval(*this, ctx);

    var_t operator ()(const var_t &d1) const
        calculator_context const ctx(d1);
        return proto::eval(*this, ctx);

    var_t operator ()(const var_t &d1, const var_t &d2) const
        calculator_context const ctx(d1, d2);
        return proto::eval(*this, ctx);


// Define some placeholders (notice they're wrapped in calculator_expression<>)
calculator_expression<proto::terminal< placeholder< 1 > >::type> const _1;
calculator_expression<proto::terminal< placeholder< 2 > >::type> const _2;

// Now, our arithmetic expressions are immediately executable function objects:
int main()
  BOOST_PROTO_AUTO(expr, _1 = _2);
  var_t a1(1), a2(2.5);
  expr(a1, a2);
  return 0;

Boost list run by bdawes at, gregod at, cpdaniel at, john at