Как прочитать произвольное количество значений, используя std :: copy? - PullRequest
8 голосов
/ 30 октября 2008

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

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() ) );

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

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

Ответы [ 8 ]

3 голосов
/ 30 октября 2008

Вы можете получить из istream_iterator .
Хотя использование метода генератора 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())
            );
}
3 голосов
/ 11 декабря 2008

Использование:

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

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

std::istream_iterator<int>();
2 голосов
/ 30 октября 2008

Рассматривая это немного, я не думаю, что чтение непосредственно в набор будет работать, так как вам нужно вызвать 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());

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

2 голосов
/ 30 октября 2008

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

1 голос
/ 06 апреля 2011

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

my_set.insert(std::istream_iterator<int>(ins), std::istream_iterator<int>());
1 голос
/ 31 октября 2008

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

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 .

0 голосов
/ 30 октября 2008

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

0 голосов
/ 30 октября 2008

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

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

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

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;
...