Построение вектора с помощью итераторов istream
Я помню, как однажды увидел умный способ использования итераторов для чтения всего двоичного файла в вектор. Выглядело это примерно так:--4-->
#include <fstream>
#include <ios>
#include <iostream>
#include <vector>
using namespace std;
int main() {
ifstream source("myfile.dat", ios::in | ios::binary);
vector<char> data(istream_iterator(source), ???);
// do stuff with data
return 0;
}
идея в том, чтобы использовать vector
конструктор диапазона итераторов путем передачи входных итераторов, которые задают весь поток. Проблема в том, что я не уверен, что передать для конечного итератора.
как создать istream_iterator
для конца файла? Я что, совсем забыл эту идиому?
2 ответов
вы хотите std::istreambuf_iterator<>
, для сырья. The std::istream_iterator<>
для форматированного ввода. Что касается конца файла, используйте конструктор по умолчанию итератора потока.
std::ifstream source("myfile.dat", std::ios::binary);
std::vector<char> data((std::istreambuf_iterator<char>(source)),
std::istreambuf_iterator<char>());
редактировать к самый неприятный синтаксический анализ C++. Спасибо, @UncleBens.
в C++11 можно:
std::ifstream source("myfile.dat", std::ios::binary);
std::vector<char> data(std::istreambuf_iterator<char>(source), {});
эта более короткая форма позволяет избежать самой неприятной проблемы разбора из-за {}
аргумент, который устраняет двусмысленность того, что он является аргументом или формальным параметром.
ответ@wilhelmtell также может быть обновлен, чтобы избежать этой проблемы, приняв инициализатор скобки для data
. Еще на мой взгляд, используя {}
проще и превратить форму инициализации не имеет значения.
редактировать
или, если мы std::lvalue
(и, возможно,std::xvalue
вместо std::move
):
#include <vector>
#include <fstream>
template <typename T>
constexpr T &lvalue(T &&r) noexcept { return r; }
int main() {
using namespace std;
vector<char> data(
istreambuf_iterator<char>(lvalue(ifstream("myfile.dat", ios::binary))),
{}
);
}