C++20范围太多|运算符? [英] C++20 ranges too many | operators?

查看:28
本文介绍了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解决。


这涉及到一些非常复杂的机制。

  • Tvalues | std::views::filter(even) | std::views::transform(square)的迭代器类型,
  • Rstd::reverse_iterator<T>

result3的初始值设定项中:

  1. ... | take(4)的迭代器类型为std::counted_iterator<R>
  2. std::counted_iterator<R>iterator_traits与部分专业化认证std::iterator_traits<std::counted_iterator<I>>匹配。
  3. 上述部分专业化认证源自std::iterator_traits<I>
  4. std::iterator_traits<R>由主模板生成:提供名为iterator_category的成员,但不提供名为iterator_concept的成员。
  5. Riterator_categoryT的相同。
  6. Titerator_categoryinput_iterator_tag,因为其解引用运算符不返回引用,这是C++17 ForwardIterator要求不允许的。(Titerator_conceptbidirectional_iterator_tag。)

所以最后std::iterator_traits<std::counted_iterator<R>>没有提供iterator_concept,它的iterator_categoryinput_iterator_tag

因此,... | take(4)的结果无法对bidirectional_range建模,因此被views::reverse拒绝。

(... | take(4)的迭代器类型在filter从管道中移除时不是counted_iterator;当transform从管道中移除时iterator_category不是input_iterator_tag。因此result1result2不会触发此错误。)

这实质上是LWG 3408

这篇关于C++20范围太多|运算符?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆