Vinícius
Vinícius

Reputation: 15746

Multiple getline implementation

I usually use std::getline to read console input for online programming challenges, I've solved quite a bunch now and I've become weary of writing multiple std::getline(std::cin, str1); std::getline(std::cin, str2); std::getline(std::cin, str3);...

So I was writing my own multiple readlines using variadic templates and I just need a quick review if this stands correct, because it seems to me that getlines(first) is not returned? Would while still evaluate if nothing is input on s1?

#include <iostream>
#include <string> //getline
#include <type_traits> //std::is_same

template<typename F>
std::istream& getlines(F& first)
{
    return std::getline(std::cin, first);
}

template<typename F, typename...O>
std::istream& getlines(F& first, O&... others)
{
    static_assert(std::is_same_v<decltype(first), std::string&>, "error: template getlines must be of std::string type");
    getlines(first); //how is this returned?
    return getlines(others...);
}

int main()
{
    std::string s1, s2, s3;
    while (getlines(s1, s2, s3))
    {
        std::cout << s1 << s2 << s3 << std::endl;
    }
}

Upvotes: 1

Views: 84

Answers (1)

Daniel Jour
Daniel Jour

Reputation: 16156

it seems to me that getlines(first) is not returned? Would while still evaluate if nothing is input on s1?

The return value of getlines is istream & ... and it is indeed not used. That doesn't matter much, though, because you have a reference to that stream eitherway (std::cin). So even if s1 can not be set due to EOF or some other condition, the corresponding flags are set in std::cin and thus once you return it (which you do at the end) it's tested in the condition of the while loop.

The missed opportunity here is that you can exit early when that first getlines already fails. E.g:

template<typename F>
std::istream& getlines(F& first)
{
    return std::getline(std::cin, first);
}

template<typename F, typename...O>
std::istream& getlines(F& first, O&... others)
{
    static_assert(std::is_same_v<decltype(first), std::string&>, "error: template getlines must be of std::string type");
    if (! getlines(first)) return std::cin;
    return getlines(others...);
}

Btw, here's what I came up with:

template<typename... Strings>
std::istream & getlines(Strings &... strings) {
    for (auto & str : {std::ref(strings)...}) {
        if (! std::getline(std::cin, str.get())) break;
    }
    return std::cin;
}

Upvotes: 1

Related Questions