2
votes
template <typename T>
T getUserInput(std::string prompt = "")
{
    T input;
    std::cout << prompt;
    if (std::is_same<T, std::string>::value)
    {
        std::getline(std::cin, input);
    }
    else
    {
        std::cin >> input;
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }
    return input;
}

I'm trying to use getline instead of cin when the type is a string (in order to include whitespace), however I get a bunch of errors saying that I didn't provide enough arguments for std::getline. I've also tried to do this:

    if (std::is_same<T, std::string>::value)
    {
        std::string sInput = "";
        std::getline(std::cin, sInput);
        return sInput;
    }

But I get an error saying I can't convert from 'std::string' to 'T'. How can I make it so it treats T as std::string?

Edit: Here's how I'm calling it:

int main()
{
    int x = getUserInput<int>("Please type a number: ");
    std::cout << x << '\n';
    std::string test = getUserInput<std::string>("Please type a string: ");
    std::cout << test << '\n';
}
2

2 Answers

3
votes

When you call the function with some T other than std::string, then the getline code will not compile, since all the code needs to be compiled regardless of whether the branch is taken, or not.

To avoid compiling the branch with the getline when not needed, you can use if constexpr, like this:

if constexpr (std::is_same_v<T, std::string>)
{
    std::getline(std::cin, input);
}
else
{
    std::cin >> input;
}

Here's a demo.

1
votes

Another option besides if constexpr (which there is nothing wrong with) is function overloading and/or specialization, e.g.:

// default version if not specialized
template<typename T>
T doUserInput()
{
    T input;
    std::cin >> input;
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    return input;
}        

template<>
std::string doUserInput() 
{
    std::string s;
    std::getline(std::cin, s);
    return s;
}

template <typename T>
T getUserInput(std::string prompt = "")
{
    std::cout << prompt;
    return doUserInput<T>();
}