2 votes

Comment créer une hiérarchie de différents "générateurs" d'objets en C++11 ordinaire ?

Ce dont j'ai besoin, c'est de la hiérarchie de classes suivante (donnée ici sous forme de croquis) :

class DataClass {}

class AbstractGenerator {
public:
    // Generates DataClass objects one by one. In a lazy manner
    virtual DataClass produce() = 0;
}

class RandGenerator : AbstractGenerator {
public:
    RandGenerator(int maximal_int) : maximal(maximal_int) {}
    DataClass produce() {
        // get a random number from 0 to this->maximal
        // make a DataClass object from the random int and return it
    }

private:
    int maximal;
}

class FromFileGenerator : AbstractGenerator {
public:
    FromFileGenerator(string file_name) : f_name(file_name) {}
    DataClass produce() {
        // read the next line from the file
        // deserialize the DataClass object from the line and return it
    }

private:
    string f_name;
}

Ce que je veux soutenir pour les deux RandGenerator y FromFileGnerator est :

RandGenerator rg();
for (DataClass data : rg) {...}

Et aussi une méthode pour prendre "les n premiers éléments du générateur".

Quels sont les outils appropriés dans le C++11 ordinaire que l'on pourrait utiliser pour réaliser cela, ou ce qui s'en rapproche le plus dans le C++11 ?

3voto

Mooing Duck Points 27497

boost::function_input_iterator est l'outil normal pour ce travail, mais puisque vous voulez du C++ "ordinaire", nous pouvons simplement réimplémenter le même concept.

class generator_iterator {
   std::shared_ptr<AbstractGenerator> generator;
public:
   using iterator_category = std::input_iterator_tag;
   generator_iterator(std::shared_ptr<AbstractGenerator> generator_)
       :generator(generator_) {}

   DataClass operator*(){return generator->produce();}
   generator_iterator& operator++(){return *this;}
   generator_iterator operator++(int){return *this;}
   //plus all the other normal bits for an output_iterator
};

Et puis dans votre AbstractGenerator fournir begin y end méthodes.

generator_iterator begin() {return {this};}
generator_iterator end() {return {nullptr};} //or other logic depending on how you want to detect the end of a series

1voto

Daniel Jour Points 6551

Ajouter un begin y end à la fonction membre AbstractGenerator qui renvoient des itérateurs qui appellent les produce fonction membre.

Un tel itérateur ( Démonstration ) pourrait ressembler à ceci :

template<typename Fn>
struct CallRepeatedlyIterator
{
    using iterator_category = std::input_iterator_tag;
    using value_type = typename std::result_of<Fn()>::type;

    // Not sure if that's correct (probably not):
    using difference_type = unsigned;
    using pointer = value_type *;
    using reference = value_type &;

    bool is_end;
    union {
        Fn fn;
    };
    union {
        value_type buffer;
    };

    value_type operator*() const
    {
        return buffer;
    }

    CallRepeatedlyIterator & operator++()
    {
        buffer = fn();
        return *this;
    }

    CallRepeatedlyIterator()
    : is_end(true)
    {}

    explicit CallRepeatedlyIterator(Fn f)
    : is_end(false)
    {
        new (&fn) Fn(f);
        new (&buffer) value_type(fn());
    }

    bool operator==(CallRepeatedlyIterator const & other) const
    {
        return is_end && other.is_end;
    }

    bool operator!=(CallRepeatedlyIterator const & other) const
    {
        return !(*this == other);
    }

    // NOTE: A destructor is missing here! It needs to destruct fn and buffer 
    //       if its not the end iterator.
};

Maintenant, votre begin retourne un tel itérateur qui appelle produce (par exemple, en utilisant un lambda de capture par référence) et end renvoie un itérateur "final".

Cela signifie que votre for s'éterniserait (aucun moyen d'atteindre l'itérateur de fin) !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X