Hi everyone, According to standard

8.6.4 The range-based for statement

The range-based for statement


for ( init-statementopt for-range-declaration : for-range-initializer ) statement

is equivalent to

{
init-statementopt auto &&range = for-range-initializer ;
auto begin = begin-expr ;

auto end = end-expr ;

for ( ; begin != end ; ++begin ) { 

for-range-declaration = * begin ;

statement 

}

begin-expr and end-expr are determined as follows:


This means that if I have code like this, it will not compile, regardless of the fact that I provided begin() and end() in my class.


#include <iostream>
#include <memory>
#include <vector>

template<typename Iter>
struct range {

  range(Iter b, Iter e)
      : _begin(b)
      , _end(e)
  {}

  Iter begin() && {
      return _begin;
  }

  Iter end() && {
      return _end;
  }

private:
  Iter _begin;
  Iter _end;
};

template<std::size_t N, typename Container>
auto head(const Container& cnt) {
  auto b = cnt.begin();
  auto e = b;
  std::advance(e, N);
  return range(b, e);
}

int main() {
 
  std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

  for(auto v : head<7>(v)) {
      std::cout << v << std::endl;
  }

  return 0;
}


The code introduces a template class range designed to represent a range of elements using iterators. Notably, it employs rvalue references (`&&`) for the begin() and end() member functions. Additionally, the code includes a template function head that extracts the first N elements from a container.


Proposal


If I rewrite the range-based for like this

int main() {
 
  std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

  // for(auto v : head<7>(v)) {
  //     std::cout << v << std::endl;
  // }

  {
      auto&& range = head<7>(v);
      auto begin = std::forward<decltype(range)>(range).begin();
      auto end = std::forward<decltype(range)>(range).end();
      for ( ; begin != end ; ++begin ) {
          auto v = * begin ;
          std::cout << v << std::endl;
      }
  }

  return 0;
}



it will work properly, and the `begin()` and `end()` functions that are provided will be called. 

I think this might be beneficial in cases where we want to avoid iterator invalidation, and we can encourage our class users to use it as an rvalue in such a context.


Why is the range variable not forwarded? Is there a specific reason for this?