Я бы ожидал, что после, указывающего на символ n
символов после того, как он начнется. Вместо этого он указывает на последний прочитанный символ. Почему это? то есть, если я делаю in_stream.tellg() до и после copy_n, они отличаются не на n
, а на (n-1)
. Если бы я прочитал n
персонажей с in_stream.read
, то позиция была бы продвинута на n
.Почему std :: copy_n не увеличивает итератор ввода n раз?
std::istreambuf_iterator<char> buf_iter(in_stream);
std::copy_n(buf_iter, n, sym.begin());
Я посмотрел на реализацию, и это явно делает это специально, пропуская окончательный приращение.
Другой пост here упоминает, что приращения от итератора, когда он подключен к, скажем, cin
, вызовет слишком много читает, так как чтение делается на operator++()
. Это звучит как проблема с cin
- почему это не прочитанное на operator*()
?
Указывает ли это стандарт в любом месте? Документы я видел, не говоря уже, что происходит с от итератора, и я видел два разных страниц, которые дают «правильные возможные реализации», которые делают каждый из поведения:
template< class InputIt, class Size, class OutputIt>
OutputIt copy_n(InputIt first, Size count, OutputIt result)
{
if (count > 0) {
*result++ = *first;
for (Size i = 1; i < count; ++i) {
*result++ = *++first;
}
}
return result;
}
while at cplusplus.com we have:
template<class InputIterator, class Size, class OutputIterator>
OutputIterator copy_n (InputIterator first, Size n, OutputIterator result)
{
while (n>0) {
*result = *first;
++result; ++first;
--n;
}
return result;
}
Как сделать п считывает и приводит к тем же содержанием в результате. Однако первый увеличит только «первый» итератор n-1
раз, а второй увеличит его n
раз.
Что дает? Как написать переносимый код? Я могу использовать tellg
, а затем seekg
, но тогда я мог бы просто сделать цикл вручную (тьфу!).
Обратите внимание, что я не пытаюсь читать из итератора после вызова copy_n
, а я хочу прочитать от основного потока после вызова copy_n
, и проблема заключается в том, что copy_n
остается наведение на байтах коротких, где Я ожидал, что это произойдет. Сейчас я собираюсь с несколько отвратительным, но, по-видимому портативным:
auto pos = in_stream.tellg();
std::istreambuf_iterator<char> buf_iter(in_stream);
std::copy_n(buf_iter, cl, sym.begin());
in_stream.seekg(pos + cl);
uint64_t foo;
in_stream.read(reinterpret_cast<char *>(&foo), 8);
Кстати, в случае, если его не ясно, я стараюсь, чтобы избежать копирования данных в буфер, а затем снова в строку sym
.
@DaveS: Двигаясь из моей конкретной проблемы, вот простая программа, которая не выводит то, что я бы ожидать в связи с тем, что входной итератор не увеличивается в последний раз:
#include <algorithm>
#include <string>
#include <iostream>
#include <fstream>
int main(int argc, const char * argv[])
{
std::ifstream in("numbers.txt");
std::istreambuf_iterator<char> in_iter(in);
std::ostreambuf_iterator<char> out_iter(std::cout);
std::copy_n(in_iter, 3, out_iter);
std::cout << std::endl;
std::copy_n(in_iter, 3, out_iter);
std::cout << std::endl;
std::copy_n(in_iter, 3, out_iter);
std::cout << std::endl;
return 0;
}
файл вход только "\n"
Я получаю:
012
234
456
Из-за побочного эффекта istreambuf_iterator::operator++()
это даст другой результат, если бы copy_n
был реализован для увеличения итератора ввода n
раз.
@aschepler: Необходимо, чтобы захватить локальный параметр, но я буду с ним:
std::generate_n(sym.begin(), cl, [&in_stream](){ return in_stream.get(); });
Или как насчет: 'std :: generate_n (sym.begin(), cl, []() {return in_stream.get();});'? – aschepler
Я спросил список рассылки для обсуждения в стандарте C++. Может быть, кто-то может объяснить это обоснование. Тема здесь: https://groups.google.com/a/isocpp.org/forum/#!topic/std-discussion/UdnfYg7HPjg – Brian