Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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).

like image 885
Bartek Banachewicz Avatar asked Sep 05 '12 10:09

Bartek Banachewicz


People also ask

How do you initialize a constant variable?

Variables can be declared as constants by using the “const” keyword before the datatype of the variable. The constant variables can be initialized once only. The default value of constant variables are zero. A program that demonstrates the declaration of constant variables in C using const keyword is given as follows.

How do you initialize a constant in C++?

A constant variable must be initialized at its declaration. To declare a constant variable in C++, the keyword const is written before the variable's data type. Constant variables can be declared for any data types, such as int , double , char , or string .

Is it necessary to initialize const variables?

In C++ the const keyword has been improved and you can declare real const values. That's why it has to be initialized before compiling the code. The rule is slightly different: to be used in an integral constant expression, the initialization must be visible to the compiler.

Can we increment const variable?

The constant variable values cannot be changed after its initialization. In this section we will see how to change the value of some constant variables. If we want to change the value of constant variable, it will generate compile time error.


1 Answers

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.

like image 91
Xeo Avatar answered Oct 15 '22 00:10

Xeo