Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the point of constexpr end istream (sentinel) iterators?

N2976 suggested adding constexpr to some spots in the standard library. It notes that iostreams are inappropriate for constexpr EXCEPT end iterators. So istream_iterator and istreambuf_iterator were given constexpr default constructors and that's about it. For example, you can see in the libstdc++ implementation that constexpr only appears once in the entire file. The LWG that sparked this change was #1129. It says:

istream_iterator and istreambuf_iterator should support literal sentinel values. The default constructor is frequently used to terminate ranges, and could easily be a literal value for istreambuf_iterator, and istream_iterator when iterating value types. [Rest omitted]

This doesn't make a whole lot of sense to me. Can someone show me an example of what they mean?

N3308 is another paper that mentions but doesn't explain the issue:

Some of the istream_iterator<T> constructors are required to be constexpr if T is a literal type. The intention is to allow existing implementation technique of storing a type of T inline to continue to work. [libstdc++ does this, _Tp _M_value] However, it actually rules out this technique: the default and copy constructors of T need not be marked constexpr, and if they are not, the istream_iterator<T> constructors could not be instantiated as constexpr.

The above explains the trivial copy constructor and destructor, but not why the default constructor is marked constexpr.

Furthermore, testing on online GCC 5.2.0, I copied libstdc++'s implementation. The only change is I removed constexpr from istream_iterator(). In both cases, the assemblies are identical.

With constexpr

Without constexpr

like image 596
user5353075 Avatar asked Sep 19 '15 07:09

user5353075


1 Answers

An example of an-end of stream iterator being used as a sentinel value is here:

// istream_iterator example
#include <iostream>     // std::cin, std::cout
#include <iterator>     // std::istream_iterator

int main () {
  double value1, value2;
  std::cout << "Please, insert two values: ";

  std::istream_iterator<double> eos;              // end-of-stream iterator
  std::istream_iterator<double> iit (std::cin);   // stdin iterator

  if (iit!=eos) value1=*iit;

  ++iit;
  if (iit!=eos) value2=*iit;

  std::cout << value1 << "*" << value2 << "=" << (value1*value2) << '\n';

  return 0;
}

http://www.cplusplus.com/reference/iterator/istream_iterator/istream_iterator/

Declaring this a constexpr allows the compiler to fold calls that create end-of-stream iterators into constants, rather than calling a function each time. It might otherwise have to do so on each iteration of a loop.

like image 136
Davislor Avatar answered Oct 18 '22 14:10

Davislor