40

我为此代码使用 g++ 10.2。有谁知道为什么我最后一个编译器std::views::reverse错误results3

#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

4

2 回答 2

35

TL;DR:在这种情况下,结果的迭代器类型std::views::takestd::counted_iterator,它有时无法在预期不会失败时对迭代器概念进行建模。这是LWG 3408,由P2259解决。


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

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

在 的初始化程序中result3

  1. 的迭代器类型... | take(4)std::counted_iterator<R>
  2. iterator_traitsforstd::counted_iterator<R>匹配偏特化std::iterator_traits<std::counted_iterator<I>>
  3. 所述部分专业化源自std::iterator_traits<I>.
  4. std::iterator_traits<R>从主模板生成:它提供了一个名为 的成员iterator_category,但没有提供一个名为 的成员iterator_concept
  5. iterator_categoryR的相同T
  6. iterator_categoryof Tis ,因为它的input_iterator_tag解引用运算符不返回引用,这是 C++17 ForwardIterator 要求所不允许的。(的iterator_conceptTbidirectional_iterator_tag

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

因此,... | take(4)模型失败的结果bidirectional_range,因此被拒绝views::reverse

(的迭代器类型... | take(4)不是从管道中删除的counted_iterator时间filteriterator_category不是input_iterator_tagtransform管道中删除的时间。因此result1result2不要触发此错误。)

这本质上是LWG 3408

于 2021-02-10T11:43:12.867 回答
6

编辑似乎 MSVC 表现出相同的行为,所以我的回答中的结论可能不正确。

我认为这是take_view.

引用(强调我的)上的cppreference页面:take_view

当底层视图 V 对各个概念进行建模时,take_view对 contiguous_range、random_access_range、bidirectional_range 、 forward_range、input_range 和sized_range 进行建模。

考虑以下代码,我们看到输入范围是 a bidirectional_range

 auto input_to_take = values
  | std::views::filter(even)
  | std::views::transform(square)
  | std::views::reverse;

static_assert(std::ranges::bidirectional_range<decltype(input_to_take)>); // No error here.

但是,在将该范围传递到之后,take_view它不再是bidierctional_range.

auto t = take_view(input_to_take, 4);
static_assert(std::ranges::bidirectional_range<decltype(t)>); // Error (constraints not satisfied)

我认为这与 cppreference 上写的内容相矛盾。

现在拍摄视图不是双向视图,您的示例中的以下反向视图无法编译,因为它期望 abidirectional_range作为输入。

现场示例在这里

于 2021-02-10T08:32:45.020 回答