2008-12-03 6 views
18

Supposons qu'une fonction de modèle en C++ effectue un travail utile mais génère également une séquence de valeurs via un itérateur de sortie. Supposons maintenant que cette séquence de valeurs soit parfois intéressante, mais qu'elle ne soit pas utile à d'autres. Y a-t-il une classe d'itération prête à l'emploi dans la STL qui peut être instanciée et transmise à la fonction et ignorera les valeurs que la fonction essaye d'assigner à l'itérateur de sortie? En d'autres termes, envoyez toutes les données à/dev/null?Suppression de la sortie d'une fonction nécessitant un itérateur de sortie

Répondre

3

Avez-vous Boost disponible? Si oui, vous pouvez utiliser un function_output_iterator enveloppant une fonction vide.

Ce n'est pas idéal cependant. Quel que soit l'itérateur que vous utiliserez, vous devrez créer une instance du type value_type pour l'opérateur return *, même s'il le rejette ensuite.

4

Il n'est pas difficile d'en écrire un.

template<typename T> 
class NullOutputIterator 
{ 
public: 
    NullOutputIterator() {} 
    NullOutputIterator& operator++() { return *this; } 
    NullOutputIterator& operator++(int) { return *this; } 
    T& operator*() { return m; } 
    T* operator->() { return &m; } 
private: 
    T m; 
}; 

Je n'ai pas testé cela, et il manque probablement quelque chose d'important, mais je pense que c'est l'idée.

+1

L'idée est bonne, mais je ne pense pas que vous ayez besoin de: T * operator ->() {return & m; } Et vous devriez dériver de stl :: output_iterator Avec cette implémentation, une copie de T est exécutée à chaque affectation via l'itérateur de sortie. Y a-t-il moyen d'éviter cela? –

20

La STL ne fournit pas un tel itérateur. Mais vous pouvez coder vous-même (testé ce code):

struct null_output_iterator : 
    std::iterator< std::output_iterator_tag, 
        null_output_iterator > { 
    /* no-op assignment */ 
    template<typename T> 
    void operator=(T const&) { } 

    null_output_iterator & operator++() { 
     return *this; 
    } 

    null_output_iterator operator++(int) { 
     return *this; 
    } 

    null_output_iterator & operator*() { return *this; } 
}; 

Il n'a pas besoin de données en utilisant lui-même à la suite de operator*. Le résultat de *it = x; n'est pas utilisé dans les exigences de l'itérateur de sortie, donc nous pouvons lui donner un type de retour de void.


Editer: Passons au fonctionnement de ce operator*. La norme dit dans 24.1.2/1 sur les exigences d'un itérateur de sortie que dans ces deux cas:

*it = t; 
*it++ = t; 

Que le résultat de ces expressions n'est pas utilisé. Ce qui fait de ce travail:

null_output_iterator it; 
*it; // returns a null_output_iterator& per definition of the `operator*`. 
*it = some_value; // returns void per definition of the templated `operator=`. 

Maintenant, on n'a pas besoin d'avoir des données que nous revenons à operator*: Nous utilisons juste le iterator lui-même. Notez que l'opérateur basé sur des modèles ne remplace pas l'opérateur d'affectation de copie intégré. C'est toujours fourni.

+0

Pourriez-vous mieux expliquer l'opérateur *? –

+0

Il est utilisé en combinaison avec l'opérateur basé sur un gabarit. Tricky, j'utiliserais une classe auxiliaire imbriquée dev_null. En outre, je laisserais l'opérateur ++ (int) retourner * ceci immédiatement. Cette version est inefficace. – MSalters

+0

msalters, l'état de la sémantique opérationnelle indique qu'un nouvel objet est renvoyé :) –

0

Je le mien basé sur std::back_insert_iterator, mais sans le conteneur:

#include <iterator> 

template<typename T> 
class NullOutputIter 
    : public std::iterator<std::output_iterator_tag,void,void,void,void> 
{ 
public: 
    NullOutputIter &operator=(const T &) { return *this; } 
    NullOutputIter &operator*() { return *this; } 
    NullOutputIter &operator++() { return *this; } 
    NullOutputIter operator++(int) { return *this; } 
}; 

Ceci est similaire à la réponse de Johannes, mais sans le modèle operator= qui prend tout. J'aime la frappe forte; Je veux *it = wrong_type_thing être une erreur de compilation. En outre, cela utilise void pour les différents paramètres de modèle à std::iterator, comme les itérateurs de sortie dans la bibliothèque standard.

Ceci est également similaire à la solution de Mark, mais (a) il hérite correctement de std::iterator et (b) il n'a pas la variable d'état interne non nécessaire.

Questions connexes