Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::reduce with functor

Tags:

c++

libstdc++

I tried to use std::reduce with a functor to calculate the number of characters in an array. GCC gives an error, while it compiles and works in MSVC. link here

#include <iostream>
#include <array>
#include <numeric>
#include <cstring>

int main()
{
    std::array arr{ "Mickey","Minnie","Jerry" };
    struct StringLength
    {
        auto operator()(const char* l, size_t r)
        {
            return strlen(l) + r;
        }
        auto operator()(size_t l, const char* r)
        {
            return l + strlen(r);
        }
        auto operator()(const char* l, const char* r)
        {
            return strlen(l) + strlen(r);
        }
        auto operator()(size_t l, size_t r)
        {
            return l + r;
        }
    };
    std::cout << std::reduce(arr.begin(), arr.end(), size_t{}, StringLength());
    // this ^ works in MSVC
}

GCC 10.1 error because important information should not be hidden behind a link:

/opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/numeric:
In instantiation of '_Tp std::reduce(_InputIterator, _InputIterator, _Tp, _BinaryOperation)
[with _InputIterator = const char**; _Tp = long unsigned int;
 _BinaryOperation = main()::StringLength]':

<source>:29:78:   required from here

/opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/numeric:263:21: error:
static assertion failed

  263 |       static_assert(is_convertible_v<value_type, _Tp>);
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
like image 557
sz ppeter Avatar asked Jun 21 '20 14:06

sz ppeter


1 Answers

I agree with dewaffled that this is a bug. The libstdc++ implementation of std::reduce looks like this:

template<typename InputIt, typename Tp, typename BinOp>
Tp reduce(InputIt first, InputIt last, Tp init, BinOp binary_op) {
    using value_type = typename iterator_traits<InputIt>::value_type;
    static_assert(is_invocable_r_v<Tp, BinOp&, Tp&, Tp&>);
    static_assert(is_convertible_v<value_type, Tp>);
    // ...
}

I wasn't able to find a requirement in the standard that iterator's value_type has to be convertible into Tp. Moreover, this requirement is not necessary at all. If you remove that static assert, your code will compile just fine as it should.

Update from GCC Bugzilla

Fixed for 9.5, 10.4 and 11.2.
Jonathan Wakely, 2021-06-18

like image 199
Evg Avatar answered Oct 15 '22 20:10

Evg