无法编译 std::reduce 调用,而 std::累积调用编译相同的参数

Can't compile std::reduce call, while std::accumulate call compiles on the same arguments

本文关键字:调用 std 编译 参数 reduce      更新时间:2023-10-16

我一直在尝试使用c++17std::reduce算法。据说,它应该支持std::accumulate支持的相同 API,但是当使用--std=c++17clang++-9.0gcc-9.2中编译时,对std::accumulate的调用编译成功,而对std::reduce的调用则不然。

到目前为止,我尝试了几件事:

  • 定义调用内部和外部的lambda
  • 使用std::reduce<...>语法显式指定类型
  • 将重载与执行策略参数结合使用
    • #include <execution>出现错误

下面是一个示例代码,它使用std::reducestd::accumulatestd::vector中的字符串长度求和:

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <numeric>
int main() {
auto op = [](auto acc, auto val) {
return acc + val.size();
};
std::vector<std::string> v = {"a", "bb", "ccc", "dddd"};
int a = std::reduce(v.begin(), v.end(), 0, op);
int b = std::accumulate(v.begin(), v.end(), 0, op);
return 0;
}

编译失败,在调用std::reduce的行中,clang-9.0.0的以下输出:

<source>:12:13: error: no matching function for call to 'reduce'
int a = std::reduce(v.begin(), v.end(), 0, op);
^~~~~~~~~~~
/opt/compiler-explorer/gcc-9.2.0/lib/gcc/x86_64-linux-gnu/9.2.0/../../../../include/c++/9.2.0/pstl/glue_numeric_defs.h:26:1: note: candidate template ignored: deduced conflicting types for parameter '_ForwardIterator' ('__gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char> *, std::vector<std::__cxx11::basic_string<char>, std::allocator<std::__cxx11::basic_string<char> > > >' vs. 'int')
reduce(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Tp __init);
^
/opt/compiler-explorer/gcc-9.2.0/lib/gcc/x86_64-linux-gnu/9.2.0/../../../../include/c++/9.2.0/pstl/glue_numeric_defs.h:21:1: note: candidate function template not viable: requires 5 arguments, but 4 were provided
reduce(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Tp __init,
^
/opt/compiler-explorer/gcc-9.2.0/lib/gcc/x86_64-linux-gnu/9.2.0/../../../../include/c++/9.2.0/pstl/glue_numeric_defs.h:31:1: note: candidate function template not viable: requires 3 arguments, but 4 were provided
reduce(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last);
^
1 error generated.

以及来自gcc-9.2的以下输出:

<source>: In function 'int main()':
<source>:12:50: error: no matching function for call to 'reduce(std::vector<std::__cxx11::basic_string<char> >::iterator, std::vector<std::__cxx11::basic_string<char> >::iterator, int, main()::<lambda(auto:1, auto:2)>&)'
12 |     int a = std::reduce(v.begin(), v.end(), 0, op);
|                                                  ^
In file included from /opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/numeric:229,
from <source>:5:
/opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/pstl/glue_numeric_defs.h:21:1: note: candidate: 'template<class _ExecutionPolicy, class _ForwardIterator, class _Tp, class _BinaryOperation> __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2> std::reduce(_ExecutionPolicy&&, _ForwardIterator, _ForwardIterator, _Tp, _BinaryOperation)'
21 | reduce(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Tp __init,
| ^~~~~~
/opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/pstl/glue_numeric_defs.h:21:1: note:   template argument deduction/substitution failed:
<source>:12:50: note:   deduced conflicting types for parameter '_ForwardIterator' ('__gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > >' and 'int')
12 |     int a = std::reduce(v.begin(), v.end(), 0, op);
|                                                  ^
In file included from /opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/numeric:229,
from <source>:5:
/opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/pstl/glue_numeric_defs.h:26:1: note: candidate: 'template<class _ExecutionPolicy, class _ForwardIterator, class _Tp> __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2> std::reduce(_ExecutionPolicy&&, _ForwardIterator, _ForwardIterator, _Tp)'
26 | reduce(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Tp __init);
| ^~~~~~
/opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/pstl/glue_numeric_defs.h:26:1: note:   template argument deduction/substitution failed:
<source>:12:50: note:   deduced conflicting types for parameter '_ForwardIterator' ('__gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > >' and 'int')
12 |     int a = std::reduce(v.begin(), v.end(), 0, op);
|                                                  ^
In file included from /opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/numeric:229,
from <source>:5:
/opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/pstl/glue_numeric_defs.h:31:1: note: candidate: 'template<class _ExecutionPolicy, class _ForwardIterator> __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, typename std::iterator_traits<_II>::value_type> std::reduce(_ExecutionPolicy&&, _ForwardIterator, _ForwardIterator)'
31 | reduce(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last);
| ^~~~~~
/opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/pstl/glue_numeric_defs.h:31:1: note:   template argument deduction/substitution failed:
<source>:12:50: note:   deduced conflicting types for parameter '_ForwardIterator' ('__gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > >' and 'int')
12 |     int a = std::reduce(v.begin(), v.end(), 0, op);
|                                                  ^

实际上,reduceaccumulate之间的区别之一是执行策略支持。如果不需要执行策略,可以调用accumulate。因此,带有std::execution::seq的代码使用gcc-trunk成功编译:https://godbolt.org/z/ERxU_q

正如@Vittorio Romeo评论的那样,这可能是libstc++中的一个错误或尚未实现的功能,可以通过切换到libc++来使用它-libstd=libc++