Pregunta

Estoy tratando de codificar una acción opuesta a esta:

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

debería ser algo como esto:

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

Pero estoy atascado con el iterador 'final': los interadores de entrada no pueden usar std :: advance y tampoco puedo usar dos transmisiones con la misma fuente ...

¿Hay alguna forma elegante de resolver esto? Por supuesto que puedo usar for loop, pero tal vez hay algo mejor :)

¿Fue útil?

Solución

Podría derivar del istream_iterator < T > ;.
Aunque usar método generador de Daemin es otra opción , aunque generaría directamente en el conjunto en lugar de usar un vector intermedio.

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

Otros consejos

Uso:

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

Tenga en cuenta el parámetro vacío:

std::istream_iterator<int>();

Errr ... copy_n () algoritmo?

Mirando esto un poco, no creo que leer directamente en un conjunto funcione, ya que necesita llamar a insert para agregar los elementos (podría estar equivocado, es bastante temprano en la mañana aquí). Aunque mirando brevemente la documentación de STL en VS2005, creo que algo que use la función generate_n debería funcionar, por ejemplo:

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

Espero que eso haya resuelto tu problema o te haya convencido de que el ciclo no es tan malo en el gran esquema de las cosas.

¿Qué tal usar un iterador alternativo para hacer el recorrido y luego usar un objeto de función (o lambda) para llenar el contenedor?

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

Por supuesto, esto supone que tiene un compilador compatible con C ++ 0x.

Por cierto, 'counting_iterator < >' es parte de Boost.Iterator .

O podrías hacer esto:

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

Sí sdg pero cuando quiero usar otras estructuras de datos en ese archivo / secuencia? Probablemente debería escribir explícitamente aquí, quiero almacenar otras cosas después de este conjunto, esta es la razón por la que también estoy almacenando el tamaño.

(Editado: debería haber leído la pregunta más de cerca ...)

Si bien es algo sospechoso, puede obtener aproximadamente el comportamiento correcto al tener una entrada en el archivo que " fail " el primer bucle, luego borre el bit de falla en la transmisión y comience a leer más.

Datos, sin un tamaño explícito, pero así

1 1 2 3 5 8 Fibb

Alimentado al siguiente código parece hacer lo que quise decir, al menos en VS2005 con 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;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top