Reputation: 410
I'm getting a warning from GCC 10.1 about possible undefined behavior. Clang 10 does not warn.
warning: operation on 'init' may be undefined [-Wsequence-point]
| (x = ... = (init = fold_op(init, elements), 0));
| ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
Here is the snippet causing the warning:
template <typename T, typename BinaryOp, typename... Pack>
constexpr auto reverse_reduce(T init, BinaryOp&& fold_op, Pack&&... elements) -> T
{
auto x = 0;
(x = ... = (init = fold_op(init, elements), 0));
return init;
}
It's using an operator=
and fold expression hack to perform a reverse 'iteration' over the parameter pack.
Is GCC right to warn here? or is it well defined behavior?
Here is as minimal as I can make it while still reproducing the error:
auto x = 0;
auto i = 0;
((x = (i = i, 0)) = (i = i, 0))
Everything I've read about sequence points, order of evaluation, and operator precedence/associativity leads me to think that this is well defined, but there are so many rules and I'm no expert.
One thing that makes me believe the warning is correct is that when I assign the result to a constexpr
variable in clang, the result is different than in non-constexpr
evaluation.
Upvotes: 1
Views: 163
Reputation: 954
You can use lambda to get rid of the warning.
Example:
template <typename T, typename BinaryOp, typename... Pack>
constexpr auto reverse_reduce(T init, BinaryOp&& fold_op, Pack&&... elements) -> T {
auto x = 0;
auto inner = [&](const auto& v) {init = fold_op(init, v); };
(x = ... = (inner(elements), 0));
return init;
}
Upvotes: 1