Home > Back-end >  compiler error in Visual Studio when std::reduce is invoked for different iterator and init types
compiler error in Visual Studio when std::reduce is invoked for different iterator and init types

Time:11-05

Please consider the follownig simple code snippet:

template<typename T>
struct point2{ T x, y; };

template<typename T>
std::complex<T> foo(std::vector<point2<T>> const& x)
{
    std::reduce(std::execution::par_unseq, x.begin(), x.end(), std::complex<T>{},
        [&](std::complex<T> const& first, point2<T> const& second) {
            return first   std::complex<T>{ second.x, second.y };
        });
}

Using Visual Studio 2022 (with C -Language set to C 20), I'm receiving the error message

'int foo::<lambda_1>::operator ()(const std::complex &,const point2 &) const': cannot convert argument 2 from 'std::complex' to 'const point2 &'

What is going wrong here? It seems like the type to which the iterators in the definition of std::reduce point to need to be the same as the chosen init value. But this doesn't seem to be a requirement described in the C standard. Am I missing something?

CodePudding user response:

std::reduce allows elements in the set to be grouped and rearranged in any order to allow for more efficient implementations. It is required that all combinations of *first and init are valid arguments to the binary_op (quote from 27.10.4 Reduce #5):

Mandates: All of

binary_­op(init, *first),
binary_­op(*first, init),
binary_­op(init, init), and
binary_­op(*first, *first)

are convertible to T.

You seem to be looking for std::accumulate, which has the same effects, but ensures that order of evaluation is kept.


To keep possibility of using std::execution::par_unseq, you may try to add conversions between point2 and std::complex:

template<typename T>
struct point2{ 
    T x, y; 
    point2(const std::complex<T>& c): x{c.real()}, y{c.imag()} {}

    // Or replace first argument in lambda with point2<T>
    // instead of this conversion operator, and adjust the rest accordingly
    operator std::complex<T>() { return {x, y};}
};

Altough I'm not sure if the conversions won't take away the benefit of parallelizing the algorithm, you should test and profile both versions before using them.

  • Related