AMDG On 02/12/2018 06:09 PM, Zach Laine wrote:
On Mon, Feb 12, 2018 at 12:08 PM, Steven Watanabe via Boost < boost@lists.boost.org> wrote:
<snip> Unwrapping the terminals causes surprising behavior, which is only sort of fixed by automatically applying the terminal transform and making transform a no-op for non-Expressions. In particular, if the terminal transform returns an Expression, that Expression will get processed again.
Yes, I'm not entirely satisfied with this either, for the same reasons. FWIW, the design has settled here after previously not doing any automatic terminal unwrapping, but I found it substantially harder to use when that was the case. I find that code like what you wrote here infrequently trips over whether Expr is an Expression or a non-Expression type, but when it does you can write it like this:
auto operator()(plus_tag, Expr&& lhs, Expr&& rhs) { transform(as_expr(lhs), *this); transform(as_expr(rhs), *this) }
Not the greatest, but like I said, I don't think the full generality here is required all that often.
I don't think as_expr helps with the problems I'm thinking of.
Unless I'm misunderstanding something, the following
(seemingly reasonable) code will blow up the stack with
infinite recursion:
int check_int(int i)
{
assert(i >= -42 && i < 42);
return i;
}
int checked_add(int i, int j)
{
return check_int(i + j);
}
struct checked_call
{
template<class F>
int operator()(F f, int i)
{
return check_int(f(i));
}
};
struct int_checker
{
auto operator()(terminal_tag, placeholder<I>)
{
return make_expression