#GCC compiler error on std::reduce but std::accumulate works fine

14 messages · Page 1 of 1 (latest)

fossil lotus
#

This example taken straight off cppreference works fine but when I change accumulate to reduce (from what I can tell the two functions accept the same arguments and work the same in this context) it fails to compile. Any idea why?

#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>

int main()
{
    std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    auto dash_fold = [](std::string a, int b) {
        return std::move(a) + '-' + std::to_string(b);
    };
 
    //if changed to std::reduce it will not compile
    std::string s = std::accumulate(std::next(v.begin()), v.end(),
                                    std::to_string(v[0]), // start with first element
                                    dash_fold);
}

Also tried using https://www.programiz.com/cpp-programming/online-compiler/ which also has the same result. MSVC compiles fine.

deft quailBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

analog cypress
#

what's the error?

fossil lotus
#

A whole bunch of static_assert failed errors with std::is_invocable (too many errors to share fully)

/usr/local/include/c++/12.2.0/numeric: In instantiation of '_Tp std::reduce(_InputIterator, _InputIterator, _Tp, _BinaryOperation) [with _InputIterator = __gnu_cxx::__normal_iterator<int*, vector<int> >; _Tp = __cxx11::basic_string<char>; _BinaryOperation = main()::<lambda(string, int)>]':
/tmp/5orgCwD6Ya.cpp:14:32:   required from here
/usr/local/include/c++/12.2.0/numeric:292:21: error: static assertion failed
  292 |       static_assert(is_invocable_r_v<_Tp, _BinaryOperation&, __ref, _Tp&>);
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
leaden galleon
#

;compile

#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>

int main()
{
    std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    auto dash_fold = [](std::string a, int b) {
        return std::move(a) + '-' + std::to_string(b);
    };
 
    //if changed to std::reduce it will not compile
    std::string s = std::reduce(std::next(v.begin()), v.end(),
                                    std::to_string(v[0]), // start with first element
                                    dash_fold);
}
swift knollBOT
#
Compiler Output
In file included from <source>:3:
/opt/compiler-explorer/gcc-14.1.0/include/c++/14.1.0/numeric: In instantiation of '_Tp std::reduce(_InputIterator, _InputIterator, _Tp, _BinaryOperation) [with _InputIterator = __gnu_cxx::__normal_iterator<int*, vector<int> >; _Tp = __cxx11::basic_string<char>; _BinaryOperation = main()::<lambda(string, int)>]':
<source>:15:32:   required from here
   15 |     std::string s = std::reduce(std::next(v.begin()), v.end(),
      |                     ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   16 |                                     std::to_string(v[0]), // start with first element
      |                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   17 |                                     dash_fold);
      |                                     ~~~~~~~~~~
/opt/compiler-explorer/gcc-14.1.0/include/c++/14.1.0/numeric:292:21: error: static assertion failed
  292 |       static_assert(is_invocable_r_v<_Tp, _BinaryOperation&, __
analog cypress
#

I think it's failing the requirement that the return value of binary op must be convertible to T (string in your case)

#

wait no

#

it's returning a string blunder

keen berry
#

it's failing the requirement that the two parameters of the binary operator must be of the range's value type

fossil lotus
#

Ah I see, guess MSVC is non compliant here. Completely missed this when reading about the differences between the two.

If any of the following values is not convertible to T, the program is ill-formed:
binary_op(init, *first)
binary_op(*first, init)
binary_op(init, init)
binary_op(*first, *first)
#

So the range's value type must be convertible to the type of the initial value and vice versa.

#

Thanks for the help!

#

!solved