Как прочитать произвольное количество значений с помощью std :: copy?

Я пытаюсь кодировать действие, противоположное этому:

std::ostream outs; // properly initialized of course
std::set<int> my_set; // ditto

outs << my_set.size();
std::copy( my_set.begin(), my_set.end(), std::ostream_iterator<int>( outs ) );

должно получиться примерно так:

std::istream ins;

std::set<int>::size_type size;
ins >> size;

std::copy( std::istream_iterator<int>( ins ), std::istream_iterator<int>( ins ) ???, std::inserter( my_set, my_set.end() ) );

Но я застрял с итератором конца - интеграторы ввода не могут использовать std :: advance, и я также не могу использовать два потока с одним и тем же источником ...

Есть ли какой-нибудь элегантный способ решить эту проблему? Конечно, я могу использовать цикл for, но, может быть, есть что-нибудь получше :)

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
8
0
1 590
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

(Отредактировано: я должен был прочитать вопрос поближе ...)

Хотя это несколько подозрительно, вы можете получить примерно правильное поведение, если в файле есть запись, которая «выйдет из строя» в первом цикле, затем сбросит бит ошибки в потоке и начнет читать больше.

Данные без явного размера, но вот так

1 1 2 3 5 8 Fibb

Похоже, что приведенный ниже код делает то, что я имел в виду, по крайней мере, на VS2005 с STLPort.

typedef std::istream_iterator < int, char, std::char_traits ,ptrdiff_t> is_iter;
std::copy( is_iter(cin), is_iter(), inserter(my_set,my_set.end()));
cin.clear();
std::cin >> instr;

Хе-хе, вы правы, это вроде подозрительно и самое главное - на двоичном потоке работать не будет :)

Miro Kropacek 30.10.2008 17:01

Да, SDG, но когда я хочу использовать другие структуры данных в этом файле / потоке? Я, наверное, должен явно написать здесь, я хочу сохранить еще что-то после этого набора, это причина, по которой я также сохраняю размер.

Errr ... Алгоритм copy_n ()?

«Эта функция является расширением SGI; она не является частью стандарта C++». И это очень верно, по крайней мере, этого не хватает в VS2008. Но симпатичный, я чуть было не хотел винить себя, как это возможно, я не заметил этого;)

Miro Kropacek 30.10.2008 17:00

Немного посмотрев на это, я не думаю, что чтение непосредственно в набор сработает, так как вам нужно вызвать в нем insert, чтобы фактически добавить элементы (я могу ошибаться, здесь довольно рано). Хотя вкратце взглянув на документацию STL в VS2005, я думаю, что что-то с использованием функции generate_n должно работать, например:

std::istream ins;
std::set<int> my_set;
std::vector<int> my_vec;

struct read_functor
{
    read_functor(std::istream& stream) :
        m_stream(stream)
    {
    }

    int operator()
    {
        int temp;
        m_stream >> temp;
        return temp;
    }
private:
    std::istream& m_stream;
};

std::set<int>::size_type size;
ins >> size;
my_vec.reserve(size);

std::generate_n(my_vec.begin(), size, read_functor(ins));
my_set.insert(my_vec.begin(), my_vec.end());

Надеюсь, это либо решило вашу проблему, либо убедило вас, что цикл не так уж плох в общем плане.

Зачем использовать вектор в качестве промежуточного звена? Просто используйте генератор для вставки в набор (используя std :: insertter).

Martin York 30.10.2008 18:41

Было поздно, когда я сочинял ответ, и тогда он не пришел в голову. Я предполагаю, что вы бы использовали устройство для вставки, хотя для этого по-прежнему требуется создание целого другого класса, поэтому для меня цикл будет проще и, вероятно, тоже будет выглядеть лучше.

Daemin 31.10.2008 01:27
Ответ принят как подходящий

Вы можете быть производным от istream_iterator <T> .
Хотя использование Метод генератора Daemin - это еще один вариант, хотя я бы сгенерировал непосредственно в набор, а не использовал бы промежуточный вектор.

#include <set>
#include <iterator>
#include <algorithm>
#include <iostream>


template<typename T>
struct CountIter: public std::istream_iterator<T>
{
    CountIter(size_t c)
        :std::istream_iterator<T>()
        ,count(c)
    {}
    CountIter(std::istream& str)
        :std::istream_iterator<T>(str)
        ,count(0)
    {}

    bool operator!=(CountIter const& rhs) const
    {
        return (count != rhs.count) && (dynamic_cast<std::istream_iterator<T> const&>(*this) != rhs);
    }
    T operator*()
    {
        ++count;
        return std::istream_iterator<T>::operator*();
    }

    private:
        size_t  count;
};

int main()
{
    std::set<int>       x;

    //std::copy(std::istream_iterator<int>(std::cin),std::istream_iterator<int>(),std::inserter(x,x.end()));
    std::copy(
                CountIter<int>(std::cin),
                CountIter<int>(5),
                std::inserter(x,x.end())
            );
}

Хотя это очень крутое решение, следует отметить, что просто написать цикл, а не делать этого, будет короче.

Evan Teran 11.12.2008 21:32

Вы использовали dynamic_cast для неполиморфного типа. Это не должно компилироваться

Armen Tsirunyan 03.07.2011 13:04

@ Армен Цирунян: Ваш аргумент обречен на провал. Вы правы в своем утверждении, что неполиморфные типы не будут компилироваться при использовании с dynamic_cast. Тем не менее, приведенное выше компилируется и работает правильно. Таким образом, по occams razer мы пришли к выводу, что это полиморфный тип. Спасибо и спокойной ночи. :-)

Martin York 04.07.2011 01:38

Как насчет использования альтернативного итератора для выполнения обхода, а затем использования объекта функции (или лямбда-выражения) для заполнения контейнера?

istream ins;
set<int>::size_type size;
set<int> new_set;
ins >> size;
ostream_iterator<int> ins_iter(ins);

for_each(counting_iterator<int>(0), counting_iterator<int>(size),
  [&new_set, &ins_iter](int n) { new_set.insert(*ins_iter++); }
);

Конечно, это предполагает, что у вас есть компилятор, совместимый с C++ 0x.

Кстати, counting_iterator <> является частью Boost.Iterator.

Использовать:

std::copy( std::istream_iterator<int>(ins),
           std::istream_iterator<int>(),
           std::inserter(my_set, my_set.end())
         );

Обратите внимание на пустой параметр:

std::istream_iterator<int>();

Черт побери, спасибо! Могу поклясться, что пробовал это, но, похоже, не стал. Отлично работает, большое спасибо! (примечание: всегда здорово следить за собственными сообщениями :)

Miro Kropacek 01.01.2009 18:38

С другой стороны, как можно определить, например, чтение трех байтов, а не всего файла? ;) Тогда это была моя проблема с принятием вашего ответа, теперь я вспомнил.

Miro Kropacek 14.01.2009 15:48

Или вы можете сделать это:

my_set.insert(std::istream_iterator<int>(ins), std::istream_iterator<int>());

Другие вопросы по теме