Считывание файла с помощью итераторов

127
31 июля 2021, 02:40

Можно ли сделать следующее без использования классических циклов и счётчиков, а с помощью итераторов?

Сначала считать значения из файла обычным оператором << (конфигурационные переменные), потом, начиная с текущего места в файле, считать n значений в вектор с помощью итератора на текущий элемент и продвинутого итератора на n элементов. В конце считать остаток в другой вектор.

Как я себе это представляю (в файле строка 1 2 3 4 5):

#include <iostream>
#include <algorithm>
#include <vector>
#include <fstream>
#include <iterator>

int main() {
    std::ifstream file("test.txt");
    int first;
    file >> first;
    std::cout << "First: " << first << '\n';
    std::vector<int> next{std::istream_iterator<int>(file), std::next(std::istream_iterator<int>(file), 2)};
    std::cout << "Next 2 elements: ";
    std::copy(next.begin(), next.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';
    std::vector<int> rest{std::istream_iterator<int>(file), std::istream_iterator<int>()};
    std::cout << "Rest: ";
    std::copy(rest.begin(), rest.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';
}

Однако вектора оказываются пустыми. Если не использовать вектор next, то rest выведется правильно, так что проблема думаю в std::next() -- он не просто продвигает итератор, но и продвигает файловый указатель. Можно ли как то добиться желаемого?

UPD

Разобрался, почему не работает.

1) "The actual read operation is performed when the iterator is incremented, not when it is dereferenced. The first object is read when the iterator is constructed. Dereferencing only returns a copy of the most recently read object."

2) "Two stream iterators are equal if both of them are end-of-stream iterators or both of them refer to the same stream."

Вариант с сохранением итератора от @AR Hovsepyan также не работает из-за 2), хоть итераторы указывают на правильные элементы.

Можно ли сделать это как-то по-другому?

Answer 1

Используйте std::copy_n:

#include <iostream>
#include <fstream>
#include <algorithm>
#include <iterator>
#include <vector>
int main()
{
    {
        std::ofstream file{"test.txt"};
        file << "1 2 3 4 5";
    }
    std::ifstream file{"test.txt"};
    int first = 0;
    file >> first;
    std::cout << "First: " << first << '\n';
    std::vector<int> next(2);
    std::copy_n(std::istream_iterator<int>{file}, 2, next.begin());
    std::cout << "Next 2 elements: ";
    std::copy(next.begin(), next.end(), std::ostream_iterator<int>{std::cout, " "});
    std::cout << '\n';
    std::vector<int> rest{std::istream_iterator<int>{file}, {}};
    std::cout << "Rest: ";
    std::copy(rest.begin(), rest.end(), std::ostream_iterator<int>{std::cout, " "});
    std::cout << '\n';
}

Ваш код не работает из за реализаци std::istream_iterator::operator==:

Checks whether both lhs and rhs are equal. Two stream iterators are equal if both of them are end-of-stream iterators or both of them refer to the same stream.

Два итаратора равны если они оба EOF или оба ссылаются на один поток.

Таким образом следующий код всегда будет выводить true

std::ifstream file{"test.txt"};
std::istream_iterator<int> it{file};    
std::cout << std::boolalpha << (it == std::next(it, 2)) << std::endl; //true

и следовательно интервал [it, it + 2) всегда пуст

READ ALSO
Как узнать, какие dll использует процесс?

Как узнать, какие dll использует процесс?

Опираясь на это,хочу получить список dll, которые использует каждый процессЯ использую stl list, где каждая нода имеет вот такие поля:

184
С чем связано определение равенства потоковых итераторов?

С чем связано определение равенства потоковых итераторов?

Почему 2 std::istream_iterator считаются одинаковыми, даже если они указывают на разные элементы одного потока? С чем связано такое определение?

190
Как Подготовить запрос sql QT?

Как Подготовить запрос sql QT?

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

351
как разыменовать двойной указатель на класс

как разыменовать двойной указатель на класс

есть указатель на массив объектов s и указатель на s

110