1

C++20 标准在[range.adaptors.general]中说范围适配器

在迭代结果视图时懒惰地评估。

另一方面,[range.filter.view]中有一条关于 filter_view 的 begin 函数的注释,提到缓存结果。那么适配器的懒惰到什么程度呢?

执行以下代码时:

#include <iostream>
#include <ranges>

void print(std::ranges::range auto&& r)
{
    for (const auto& item : r)
    {
        std::cout << item << ", ";
    }
    std::cout << " <end of range>\n";
}

int main()
{
    using namespace std::ranges;

    bool filter = false;
    
    auto v = iota_view{4, 10} | views::filter([&filter](auto item){return filter;});

    // multipass guarantee
    static_assert(std::ranges::forward_range<decltype(v)>);

    filter = true;
    print(v);

    filter = false;
    print(v);

    filter = true;
    print(v);
}

是否保证适配器会尊重filter变量的值?如果不是,我在调用什么样的行为,它在哪里声明?

4

3 回答 3

5

请记住,在 C++ 迭代器模型中,定位和访问是两个不同的操作。但是,过滤迭代器的位置基于访问它正在过滤的范围。这就是迭代器的本质。

要找到过滤范围的开头,需要在基础范围中找到与过滤条件匹配的第一个位置。就像在过滤范围内查找下一个元素需要迭代,直到找到另一个匹配过滤条件的迭代器。

因此,获取过滤范围的起始迭代器需要访问该范围的至少一个元素。过滤迭代器尽可能地懒惰,同时仍然在做它的工作。

但是,您的特定代码显示 UB,因为您的谓词不是regular_invocable. 该标准明确要求:

调用函数调用表达式应保持相等([concepts.equality]

这意味着:

如果给定相等的输入,表达式会产生相等的输出,则表达式是保持等式的。表达式的输入是表达式操作数的集合。表达式的输出是表达式的结果和表达式修改的所有操作数。

您通过更改谓词的行为违反了该要求。

于 2021-03-23T17:21:50.363 回答
4

是否保证适配器会尊重过滤器变量的值?

不。

如果不是,我在调用什么样的行为,它在哪里声明?

这是[res.on.requirements]/3的 IFNDR :

如果声明的约束([structure.requirements])的语义要求没有在使用时建模,则程序格式错误,不需要诊断。

特别是,filter_view要求谓词评估是保持平等的(通过indirect_­unary_­predicatewhich requires predicatewhich requires regular_invocable)。结果可以自发改变的东西不符合这个要求 - 见[concepts.equality]/3

于 2021-03-23T17:33:12.567 回答
-2

演示是最好的:https ://godbolt.org/z/WxrsfTrve

int squreIt(int x)
{
    std::cout << "squreIt(" << x << ")\n";
    return x * x;
}

int main()
{
    std::array a{4, 3, 2, 1, 0, 5, 6};

    for (auto x : a | std::views::transform(squreIt) | std::views::drop(3)) {
        std::cout << "Result = " << x << '\n';
    }
    std::cout << "---------\n";
    for (auto x : a | std::views::drop(3) | std::views::transform(squreIt)) {
        std::cout << "Result = " << x << '\n';
    }
    return 0;
}

squreIt仅对打印所需的项目调用注释,无论视图顺序如何。这表明了懒惰。

于 2021-03-23T17:31:32.343 回答