Search code examples
c++istream

Skipping input stream values


Is there any easy mechanism to skip until the next whitespace with a C++ input stream (like ifstream)?

I know that I can use ignore if I know how many characters to skip or what delimiter to expect. But IMO it's ugly to use ignore when operator>> usually just reads to the next whitespace without supplying any additional parameters. I could also use a dummy, but that only makes matters worse.

Example

auto importantInfo1 = 0;
auto importantInfo2 = 0;
auto someDummy = 0; // This is ugly and doesn't clearly express the intent

file >> importantInfo1 >> someDummy >> importantInfo2;

Also in some cases I will need more than one dummy if I need to handle different datatypes in the "skip"-case.

I would imagine something like this:

file >> importantInfo1;
file.skip<int>(1);
file >> importantInfo2;

Or maybe even better:

auto importantInfo1 = 0;
auto importantInfo2 = 0;

file >> importantInfo1 >> skip<int> >> importantInfo2;

I imagine such a solution would also perform better than actually parsing and storing the value somewhere when it is never needed.

Possible solution

Made this solution using the answers provided. It's basically the same as the accepted answer, but it doesn't need a temporary. Instead, it skips the first whitespaces, then skips any character except whitespaces until whitespace is reached again. This solution may use 2 while loops but doesn't need to know about the extracted type. I'm not saying this is a high performance solution or anything fancy, but it makes the resulting code shorter, cleaner and more expressive.

template<typename CharT, typename Traits>
inline std::basic_istream<CharT, Traits>& skip(std::basic_istream<CharT, Traits>& stream)
{
    while (stream && std::isspace(stream.peek())) stream.ignore();
    while (stream && !std::isspace(stream.peek())) stream.ignore();
    return stream;
}

Solution

  • I think your idea having a manipulator to skip data is the right way to go.

    Skip 'trivial' data:

    #include <sstream>
    
    template<typename T, typename Char, typename Traits>
    inline std::basic_istream<Char, Traits>& skip(std::basic_istream<Char, Traits>& stream) {
        T unused;
        return stream >> unused;
    }
    
    int main()
    {
        std::istringstream in("1 666 2 ");
        int a;
        int b;
        in >> a >> skip<int> >> b;
        std::cout << a << b << '\n';
    }
    

    If the data gets more complex and construction/streaming becomes expensive you have to provide an specialized overload and parse char by char to skip it.