Question

J'essaie de coder les actions opposées à ceci:

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

cela devrait ressembler à ceci:

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

Mais je suis coincé avec l'itérateur 'end' - les interateurs d'entrée ne peuvent pas utiliser std :: advance et je ne peux pas non plus utiliser deux flux avec la même source ...

Existe-t-il un moyen élégant de résoudre ce problème? Bien sûr, je peux utiliser pour la boucle, mais il y a peut-être quelque chose de plus agréable:)

Était-ce utile?

La solution

Vous pouvez dériver de l'istream_iterator < T > ;.
L'utilisation de la méthode du générateur Daemin est une autre option. , bien que je génère directement dans l’ensemble plutôt que d’utiliser un vecteur intermédiaire.

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

Autres conseils

Utiliser:

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

Notez le paramètre vide:

std::istream_iterator<int>();

En regardant cela un peu, je ne pense pas que la lecture directe dans un ensemble marche, car vous devez appeler un insert dessus pour ajouter les éléments (je pourrais me tromper, il est plutôt tôt le matin ici). Bien que je regarde brièvement la documentation STL dans VS2005, je pense que quelque chose utilisant la fonction generate_n devrait fonctionner, par exemple:

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

Espérons que cela résoudra votre problème ou vous convaincra que la boucle n’est pas si mauvaise dans le grand schéma.

Pourquoi ne pas utiliser un autre itérateur pour effectuer la traversée, puis utiliser un objet fonction (ou lambda) pour remplir le conteneur?

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

Bien entendu, cela suppose que vous ayez un compilateur conforme à C ++ 0x.

BTW, 'counting_iterator < >' fait partie de Boost.Iterator .

Ou vous pouvez faire ceci:

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

Oui, mais si je veux utiliser une autre structure de données dans ce fichier / flux? Je devrais probablement écrire explicitement ici, je veux stocker un autre article après cet ensemble, c’est la raison pour laquelle j’enregistre également la taille.

(Edité: j'aurais dû lire la question de plus près ...)

Bien que quelque peu suspect, vous pouvez obtenir à peu près le bon comportement en ayant une entrée dans le fichier qui & "; échouera &"; la première boucle, puis effacez le bit d’échec du flux et commencez à lire davantage.

Données sans taille explicite, mais comme ceci

1 1 2 3 5 8 Fibb

Le code ci-dessous semble indiquer ce que je voulais dire, du moins sur VS2005 avec 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;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top