Read user input or Enter

Code

In an interactive shell application, you might want to ask the user for value, or let them stick with the default or current value. In such cases, it’s quite handy to be able to accept a press on the Enter key as a shorthand for keeping the current.

Number of runs (5): 
Snoffle variant (pink): red	

In the example above, the user has pressed enter without giving a value when prompted for number of runs, and has thus accepted the current setting of 5. In contrast, the user has decided to change the snoffle variant from pink to red. Presumably the user (and the programmer) knows the significance of all this.

The problem is that while the standard input stream std::cin is good at reading and parsing data, it will read as much as it needs, and no more. This means that for strings, it will read until the first whitespace character, so you only get one word. For ints and floats, it will ignore any initial whitespace characters, like space and newline, until it finds the beginning of a number (or an invalid character), and leave anything after the number, which may lead to there being a newline in the buffer when you come next to read a string.

The solution lies in always reading everything until newline, which is what the standalone function std::getline is for, into a string, and then, once we have the whole user input, attempt to parse it. By using a std::stringstream, we’ll be relying on the same parsing routines as std::cin would feed into. Making it a template function is only natural, since the streams (both std::cin and std::stringstream) are designed to work with ttemplate types.

#include <iostream>
#include <sstream>

/*! Read user input until Enter is pressed. 
    \tparam T type of data to read
    \param val will hold the given input, if any
    \return false if Enter was pressed at once, true if data was given
*/
template <typename T>
bool get_user_input(T& val)
{
    std::string s;
    std::getline( std::cin, s);
    if (s.empty())
        return false;
    std::stringstream ss;
    ss << s;
    ss >> val;
    return true;
}

This is very simple and straigtforward to use:

  int runs = get_number_of_runs();
  std::cout << "Number of runs (" << runs << "): ";
  if (get_user_input(runs))
    set_number_of_runs(runs);
  std::string snoffle = get_snoffle();
  std::cout << "Snoffle variant (" << snoffle << "): "
  if (get_user_input(snoffle))
    set_snoffle(snoffle);

You’ll note that we get the current value, so we can display it, and only replace it if we have been given a new one.