C++20 ranges too many | operators?(C++20范围太多|运算符?)
问题描述
我对此代码使用g++10.2。有人知道为什么我在results3的最后一个std::views::reverse出现编译器错误吗?
#include <vector>
#include <ranges>
int main() {
auto values = std::vector{1,2,3,4,5,6,7,8,9,10};
auto even = [](const auto value) {
return value % 2 == 0;
};
auto square = [](const auto value) {
return value * value;
};
auto results1 = values
| std::views::filter(even)
| std::views::reverse
| std::views::take(4)
| std::views::reverse;
auto results2 = values
| std::views::transform(square)
| std::views::reverse
| std::views::take(4)
| std::views::reverse;
auto results3 = values
| std::views::filter(even)
| std::views::transform(square)
| std::views::reverse
| std::views::take(4)
| std::views::reverse; // Error happens on this line.
}
错误片段:
...
<source>: In function 'int main()':
<source>:30:9: error: no match for 'operator|' (operand types are 'std::ranges::take_view<std::ranges::reverse_view<std::ranges::transform_view<std::ranges::filter_view<std::ranges::ref_view<std::vector<int, std::allocator<int> > >, main()::<lambda(auto:13)> >, main()::<lambda(auto:14)> > > >' and 'const std::ranges::views::__adaptor::_RangeAdaptorClosure<std::ranges::views::<lambda(_Range&&)> >')
25 | auto results3 = values
| ~~~~~~
26 | | std::views::filter(even)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
27 | | std::views::transform(square)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
28 | | std::views::reverse
| ~~~~~~~~~~~~~~~~~~~~~
29 | | std::views::take(4)
| ~~~~~~~~~~~~~~~~~~~~~
| |
| std::ranges::take_view<std::ranges::reverse_view<std::ranges::transform_view<std::ranges::filter_view<std::ranges::ref_view<std::vector<int, std::allocator<int> > >, main()::<lambda(auto:13)> >, main()::<lambda(auto:14)> > > >
30 | | std::views::reverse;
| ^ ~~~~~~~~~~~~~~~~~~~
| |
| const std::ranges::views::__adaptor::_RangeAdaptorClosure<std::ranges::views::<lambda(_Range&&)> >
...
可在此处查看完整的错误集:https://godbolt.org/z/Y7Gjqd
推荐答案
tl;dr:在这种情况下,std::views::take的结果的迭代器类型是std::counted_iterator,它有时无法在预期不会失败的情况下对迭代器概念进行建模。这是LWG 3408,由P2259解决。
这涉及到一些非常复杂的机制。
让
T为values | std::views::filter(even) | std::views::transform(square)的迭代器类型,R为std::reverse_iterator<T>。
在result3的初始值设定项中:
... | take(4)的迭代器类型为std::counted_iterator<R>。std::counted_iterator<R>的iterator_traits与部分专业化认证std::iterator_traits<std::counted_iterator<I>>匹配。- 上述部分专业化认证源自
std::iterator_traits<I>。 std::iterator_traits<R>由主模板生成:提供名为iterator_category的成员,但不提供名为iterator_concept的成员。R的iterator_category与T的相同。T的iterator_category为input_iterator_tag,因为其解引用运算符不返回引用,这是C++17 ForwardIterator要求不允许的。(T的iterator_concept为bidirectional_iterator_tag。)
所以最后std::iterator_traits<std::counted_iterator<R>>没有提供iterator_concept,它的iterator_category是input_iterator_tag。
因此,... | take(4)的结果无法对bidirectional_range建模,因此被views::reverse拒绝。
(... | take(4)的迭代器类型在filter从管道中移除时不是counted_iterator;当transform从管道中移除时iterator_category不是input_iterator_tag。因此result1和result2不会触发此错误。)
这实质上是LWG 3408。
这篇关于C++20范围太多|运算符?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:C++20范围太多|运算符?
- XML Schema 到 C++ 类 2022-01-01
- 将 hdc 内容复制到位图 2022-09-04
- 如何提取 __VA_ARGS__? 2022-01-01
- 使用 __stdcall & 调用 DLLVS2013 中的 GetProcAddress() 2021-01-01
- 从父 CMakeLists.txt 覆盖 CMake 中的默认选项(...)值 2021-01-01
- OpenGL 对象的 RAII 包装器 2021-01-01
- DoEvents 等效于 C++? 2021-01-01
- 将函数的返回值分配给引用 C++? 2022-01-01
- GDB 不显示函数名 2022-01-01
- 哪个更快:if (bool) 或 if(int)? 2022-01-01
