Home > Mobile >  ranges and temporary initializer lists
ranges and temporary initializer lists

Time:08-08

I am trying to pass what I think is a prvalue into a range adapter closure object. It won't compile unless I bind a name to the initializer list and make it an lvalue. What is happening here?

#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);
}

CodePudding user response:

When you use r | views::drop(1) to create a new view, range adaptors will automatically convert r into a view for you. This requires that the type of r must model viewable_range:

template<class T>
  concept viewable_­range =
    range<T> &&
    ((view<remove_cvref_t<T>> && constructible_­from<remove_cvref_t<T>, T>) ||
     (!view<remove_cvref_t<T>> &&
      (is_lvalue_reference_v<T> || (movable<remove_reference_t<T>> && !is-initializer-list<T>))));

Note the last requirement:

(is_lvalue_reference_v<T> || (movable<remove_reference_t<T>> && !is-initializer-list<T>))));

Since the type of r doesn't model a view, which in your case is initializer_list, it needs to be an lvalue, allowing us to freely take its address to construct a ref_view without worrying about dangling.

Or, we need it to be movable, which allows us to transfer its ownership to owning_view, which means the following is well-formed:

auto r = std::vector{42} | views::drop(1)

But in this case, we also need it not to be a specialization of initializer_list, because we can't transfer ownership of it, initializer_list always copy. That's why your example fails.

  • Related