C++20:为什么范围适配器和范围不能组合在一个表达式中?

Ang*_*ket 1 c++ c++20 std-ranges

我正在看以下片段:

std::vector<int> elements{ 1,2,3 };
// this won't compile:
elements
    | std::views::filter([](auto i) { return i % 2 == 0; })
    | std::ranges::for_each([](auto e) {std::cout << e << std::endl; });
// but this compiles:
auto view  = 
elements
    | std::views::filter([](auto i) { return i % 2 == 0; });
std::ranges::for_each(view, [](auto e) {std::cout << e << std::endl; });
 
Run Code Online (Sandbox Code Playgroud)

我看不出范围适配器(视图)和范围算法通过管道运算符的组合无法编译的原因。std::ranges::dangling我想这与我的编译器(msvc 19.29)报告的返回类型有关for_each,但我不确定......

Bar*_*rry 6

实际上,并没有任何固有的设计原因解释为什么某些算法集确实具有管道支持(视图、操作,以及to- 尽管 C++20 到目前为止仅具有视图)而其他算法却没有(参考资料中的其他所有内容<algorithm>)。管道进入for_each与管道进入一样有意义filter,只是 range-v3(以及因此的 C++20 Ranges)仅对某些事物这样做,而对其他事物则不然。

截至目前,还没有选择加入机制来使某些内容在范围意义上“可传送”(请参阅​​ P2387来更改它)。但是,一旦该论文或它的某些变体获得批准,编写一个简单地使算法可管道化的算法适配器就会变得很容易。例如,您可以这样做:

elements
  | std::views::filter([](auto i) { return i % 2 == 0; })
  | adaptor(std::ranges::for_each)([](auto e) {std::cout << e << std::endl; });
Run Code Online (Sandbox Code Playgroud)

演示(请注意,这目前取决于 libstdc++ 内部)。

库机制解决此问题的方法的一个问题是模糊性 - 这依赖于确定 iff(x, y)是可调用的,其目的是使其成为完整调用而不是部分调用。对于某些算法来说,您可能无法在这个意义上区分部分调用和完整调用(这本身可能是不让它们隐式可管道化的一个动机)。这当然是一些视图中已知的问题(zipconcat、 和join分隔符就是例子),并且本身就是针对该问题提供语言解决方案的动机之一(例如P2011)。

当然,这只会影响您是否可以编写| some_algo(args...),我在这里描述的选择加入机制可以很容易地拼写| partial(ranges::for_each, args...)| adaptor(ranges::for_each)(args...),而不是 ,这样就不会有歧义了。在我看来,这只是一个更奇怪的拼写,这就是为什么我以我的方式展示它。