'Why do C++ istreams only allow formatted-reading into an existing variable?

In C++ (and using the standard library facilities), if I want to read an integer from the standard input, I need to do this:

int x;
std::cin >> x;

And looking at the std::istream page on cppreference, it seems there is no function such as std::cin.scan<int>() which returns an int prvalue; nor is there a freestanding function std::scan<int>(std::cin) which does so.

My question is: Why?

It seems nonsensical to me to encourage people to:

  1. Define and name variables they may not need (e.g. as opposed to func_taking_an_int(std::cin.scan<int>()).
  2. Split the definition and the initialization of a variable

So what's the rationale of only supporting the operator form?

Now, I know C++ istreams go back decades, but it's still weird to me (not to mention that an extra method/function could have been added later on).


Motivation: I saw this question and realized that, to our shame, we cannot offer the poster a better way to write their program other than using an uninitialized variable. I was assuming that, surely, we can help that poster bring the definition into the same statement as the initialization... but it seems we cannot.



Solution 1:[1]

Of course there is one:

#include <iostream>
#include <iterator>

int main() {
  auto const i = *std::istream_iterator<int>(std::cin);
}

Note that this causes UB if std::cin doesn't have a valid int. You might expect it to throw an exception, but since iostreams predate exceptions, that is not how the API works. You should compare it with the end-iterator.

std::istream_iterator<int> it(std::cin), end;
auto const i = (it != end) ? *it : -1;

Finally, you might want to wrap that in a nice, reusable API:

#include <iostream>
#include <iterator>
#include <optional>

template <class T>
auto scan(std::istream& is) -> std::optional<T> {
  std::istream_iterator<int> it(std::cin), end;
  if (it != end) return std::optional(*it);
  return std::nullopt;
}

int main() {
  auto const i = scan<int>(std::cin);
  if (i) {
    return *i;
  }
  return -1;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1