2008-10-30 3 views
8

Я пытаюсь кодировать противоположное действие на это:Как читать произвольное количество значений с помощью 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())); 

Но я застрял с «концом» Итератор - входное interators может 't использовать std :: advance, и я не могу использовать два потока с одним и тем же источником ...

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

ответ

3

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

#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()) 
      ); 
} 
+2

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

+0

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

+0

@Armen Tsirunyan: Ваш аргумент - победа. Вы верны в своем утверждении, что типы non-polymorphics не будут компилироваться при использовании с dynamic_cast. Однако вышеприведенное компилируется и работает правильно. Таким образом, с помощью окклюменного ящика мы получаем вывод о том, что он является полиморфным типом. Спасибо вам и спокойной ночи. :-) –

0

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

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

данных, без явного размера, но как этот

 
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; 
+0

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

0

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

2

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

+0

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

+1

C++ 0x is добавив это также –

2

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

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

+1

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

+0

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

1

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

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.

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

0

Спасибо за идеи ребята.Даже когда эти вещи кажутся круто, я, конечно, не собирается создавать новый класс/итератор для этого ;-) Я лучше понять, почему SGI решил включить «copy_n» алгоритм теперь :)

3

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

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

Примечания пустой параметр:

std::istream_iterator<int>(); 
+0

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

+0

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

1

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

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