Are there any tricks to use std::cin to initialize a const variable?

Common std::cin usage

int X;
cin >> X;

The main disadvantage of this is that X cannot be const. It can easily introduce bugs; and I am looking for some trick to be able to create a const value, and write to it just once.

The naive solution

// Naive
int X_temp;
cin >> X_temp;
const int X = X_temp;

You could obviously improve it by changing X to const&; still, the original variable can be modified.

I'm looking for a short and clever solution of how to do this. I am sure I am not the only one who will benefit from a good answer to this question.

// EDIT: I'd like the solution to be easily extensible to the other types (let's say, all PODs, std::string and movable-copyable classes with trivial constructor) (if it doesn't make sense, please let me know in comments).


I'd probably opt for returning an optional, since the streaming could fail. To test if it did (in case you want to assign another value), use get_value_or(default), as shown in the example.

template<class T, class Stream>
boost::optional<T> stream_get(Stream& s){
  T x;
  if(s >> x)
    return std::move(x); // automatic move doesn't happen since
                         // return type is different from T
  return boost::none;
}

Live example.

To further ensure that the user gets no wall-of-overloads presented when T is not input-streamable, you can write a trait class that checks if stream >> T_lvalue is valid and static_assert if it's not:

namespace detail{
template<class T, class Stream>
struct is_input_streamable_test{
  template<class U>
  static auto f(U* u, Stream* s = 0) -> decltype((*s >> *u), int());
  template<class>
  static void f(...);

  static constexpr bool value = !std::is_void<decltype(f<T>(0))>::value;
};

template<class T, class Stream>
struct is_input_streamable
  : std::integral_constant<bool, is_input_streamable_test<T, Stream>::value>
{
};

template<class T, class Stream>
bool do_stream(T& v, Stream& s){ return s >> v; }
} // detail::

template<class T, class Stream>
boost::optional<T> stream_get(Stream& s){
  using iis = detail::is_input_streamable<T, Stream>;
  static_assert(iis::value, "T must support 'stream >> value_of_T'");
  T x;
  if(detail::do_stream(x, s))
    return std::move(x); // automatic move doesn't happen since
                         // return type is different from T
  return boost::none;
}

Live example.

I'm using a detail::do_stream function, since otherwise s >> x would still be parsed inside get_stream and you'd still get the wall-of-overloads that we wanted to avoid when the static_assert fires. Delegating this operation to a different function makes this work.


You could make use of lambdas for such cases:

   const int x = []() -> int {
                     int t;
                     std::cin >> t;
                     return t;
                 }();

(Note the extra () at the end).

Instead of writing a separate functions, this has the advantage of not having to jump around in your source file, when reading the code.

Edit: Since in the comments it was stated that this goes against the DRY rule, you could take advantage of auto and 5.1.2:4 to reduce type repetition:

5.1.2:4 states:

[...] If a lambda-expression does not include a trailing-return-type, it is as if the trailing-return-type denotes the following type:

  • if the compound-statement is of the form

    { attribute-specifier-seq(opt) return expression ; }

    the type of the returned expression after lvalue-to-rvalue conversion (4.1), array-to-pointer conversion (4.2), and function-to-pointer conversion (4.3);

  • otherwise, void.

So we could alter the code to look like this:

   const auto x = [] {
                     int t;
                     std::cin >> t;
                     return t;
                  }();

I can't decide if that is better though, since the type is now "hidden" within the lambda body...

Edit 2: In the comments it was pointed out, that just removing the type name where it is possible, does not result in a "DRY-correct" code. Also the trailing-return-type deduction in this case is currently actually an extension of MSVC++ as well as g++ and not (yet) standard.