范围和临时初始化列表

dan*_*lNJ 3 c++ c++20 std-ranges

我试图将我认为是纯右值的内容传递到范围适配器闭包对象中。除非我将名称绑定到初始值设定项列表并使其成为左值,否则它不会编译。这里发生了什么?

#include <bits/stdc++.h>

using namespace std;

int main(){
  //why does this compile?
  auto init_list = {1,2,4};
  auto v = init_list | views::drop(1);
  
  //but not this?
  // auto v2 = initializer_list<int>{1,2,4} | views::drop(1);

  //or this?
  //auto v3 = views::all(initializer_list<int>{1,2,4}) | views::drop(1);
}
Run Code Online (Sandbox Code Playgroud)

康桓瑋*_*康桓瑋 7

当您使用r | views::drop(1)创建新的时view,范围适配器会自动转换rview适合您的。这要求 的类型r必须为viewable_range

\n
template<class T>\n  concept viewable_\xc2\xadrange =\n    range<T> &&\n    ((view<remove_cvref_t<T>> && constructible_\xc2\xadfrom<remove_cvref_t<T>, T>) ||\n     (!view<remove_cvref_t<T>> &&\n      (is_lvalue_reference_v<T> || (movable<remove_reference_t<T>> && !is-initializer-list<T>))));\n
Run Code Online (Sandbox Code Playgroud)\n

请注意最后一个要求:

\n
(is_lvalue_reference_v<T> || (movable<remove_reference_t<T>> && !is-initializer-list<T>))));\n
Run Code Online (Sandbox Code Playgroud)\n

由于 的类型r不模拟 a view,在您的情况下是initializer_list,它需要是一个左值,允许我们自由地获取它的地址来构造 a ,ref_view而不必担心悬空。

\n

或者,我们需要它是movable,这允许我们将其所有权转移到owning_view,这意味着以下是格式良好的:

\n
auto r = std::vector{42} | views::drop(1)\n
Run Code Online (Sandbox Code Playgroud)\n

但在这种情况下,我们还需要它不成为 的特化initializer_list,因为我们无法转移它的所有权,initializer_list只能复制。这就是你的例子失败的原因。

\n