Как игнорировать последнюю пустую строку при использовании istream_iterator

Допустим, у меня есть простой текстовый файл 2D точек, например:

10
0.000   0.010
0.000   0.260
0.000   0.510
0.000   0.760
0.000   1.010
0.000   1.260
0.000   1.510
0.000   1.760
0.000   2.010
0.000   2.260
// Blank line here

Я использую простую структуру для ввода-вывода:

template <typename T>
struct point
{
    point (T x = 0, T y = 0) : x (x), y (y) {}

    T x ;
    T y ;

    friend std::istream& operator>> (std::istream &is, point &p) {
        is >> p.x >> p.y ;
        return is ;
    }
};

Мой оригинальный код был:

int main (void)
{
    std::string strFile = "Points.txt" ;

    std::ifstream file ;
    file.exceptions (std::ios::failbit | std::ios::badbit) ;
    std::vector <point <double> > vec ;

    try {
        file.open (strFile) ;

        int nPoints = 0 ;
        file >> nPoints ;

        for (int n = 0; n < nPoints; ++n) {
            point <double> p ;
            file >> p ;
            vec.push_back (p) ;
        }
    }

    catch (std::ios_base::failure &e) {
        std::cerr << e.what () << "\n" ;
        return 1 ;
    }

    return 0 ;
}

Это прекрасно работает, но в духе отсутствия сырых циклов я бы хотел избавиться от цикла for.

Вот мой новый код:

int main (void)
{
    std::string strFile = "Points.txt" ;

    std::ifstream file ;
    file.exceptions (std::ios::failbit | std::ios::badbit) ;
    std::vector <point <double> > vec ;

    try {
        file.open (strFile) ;

        int nPoints = 0 ;
        file >> nPoints ;

        std::copy (
            std::istream_iterator <point <double> > (file), 
            std::istream_iterator <point <double> > (), 
            std::back_inserter (vec)
        ) ;
    }

    catch (std::ios_base::failure &e) {
        std::cerr << e.what () << "\n" ;
        return 1 ;
    }

    return 0 ;
}

Все копируется нормально, но, к сожалению, чтение последней пустой строки вызывает бит сбоя.

Единственные способы, которые я могу придумать, чтобы исправить это, довольно уродливы. Я мог бы:

  • Поместите предложение "поймать-поймать" в point::operator>>() функция
  • Проверьте vec.size() в предложении catch, которое уже существует.

Есть ли элегантный способ игнорирования последней пустой строки?

1 ответ

Решение

+ Изменить

    std::copy (
        std::istream_iterator <point <double> > (file), 
        std::istream_iterator <point <double> > (), 
        std::back_inserter (vec)
    ) ;

в

    std::copy_n (
        std::istream_iterator <point <double> > (file), 
        nPoints, 
        std::back_inserter (vec)
    ) ;
Другие вопросы по тегам