https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104251

            Bug ID: 104251
           Summary: std::reduce scrambles argument order for BinaryOp
                    function call: Possible bug?
           Product: gcc
           Version: 11.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: felix.koehler at gmail dot com
  Target Milestone: ---

Created attachment 52298
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=52298&action=edit
Disable testcase test03 to compile with GCC

I experimented with std::reduce from the libstdc++ library and I get completely
different results for all slightly non-trivial cases comparing
CLANG-13.0.0/CLANG-HEAD-14.0.0 output vs GCC--10.2.0/11.1.0/HEAD 12.0.1
20220123 (experimental). (Using wandbox.org)

a) the arguments with a non-default BinOp parameter seem to get scrambled, see
attachment test01().

    vector<int> x={1,2,3,1};
    int sum;
    auto b=x.cbegin();
    auto e=x.cend();
    cout << reduce(b, e, 0, [](int sum, int i) {return sum+i+i;}) << "\t";

yields 14 for CLANG, 30 for GCC. Trace of the lambda function calls included in
the attachment.

b) Even a simple double addition lambda function does not work, if the
accumulator value requires a higher precision to hold the result, than can be
stored in the type of the sequence to be reduced. See attachment test02(). This
is probably not the intended behavior.

    vector<unsigned char>bytes = {200, 201, 202, 203};
    cout << reduce(bytes.begin(), bytes.end(), 0L,
                   [](long sum, unsigned char i) {return sum+i;});

yields the expected 806 for CLANG, GCC overflows and yields 38.

c) Using non-implicitely-convertible types for the accumulator and the reduced
function is not supported in GCC, yet CLANG compiles and runs the following
code just fine. See test03().

TLDR:
    vector<string> numbers={"eins","dos", "three", "quatre"};
    cout << reduce(numbers.begin(), numbers.end(), 0L,
                   [](size_t sum, string s) {return sum+s.size();}) << "\t";

CLANG counts 18 letters, GCC refuses compilation with an error message that the
init value 0L cannot be converted into the sequence type of string.

According to cppreference.com:
"The behavior is non-deterministic if binary_op is not associative or not
commutative. ... in other words, reduce behaves like std::accumulate except the
elements of the range may be grouped and rearranged in arbitrary order." which
seems to support the CLANG interpretation.

I'm not a language lawyer, GCC might be correct in assuming that the sequence
MUST have the same type as the result of the reduce function and you cannot
expect to get passed the accumulator value as the first argument to BinOp and
the sequence value as the second argument. However, this reduces std::reduce to
a trivial SUM/PRODUCT function with a horrible interface and really evil
implicit type-casting traps. 

This seems to be a bug in either the libstdc++ implementation or the standard
itself, please correct me, if I'm wrong.

Reply via email to