2008-12-03 31 views
18

Supongamos que hay una función de plantilla en C++ que hace un trabajo útil pero también genera una secuencia de valores a través de un iterador de salida. Ahora supongamos que esa secuencia de valores a veces es interesante, pero en otros no es útil. ¿Hay una clase de iterador lista para usar en el STL que pueda ser instanciada y pasada a la función e ignorará los valores que la función intente asignar al iterador de salida? Para decirlo de otra manera, envíe todos los datos a/dev/null?Descartando la salida de una función que necesita un iterador de salida

Respuesta

3

¿Tiene Boost disponible? De ser así, podría usar un function_output_iterator envolviendo una función vacía.

Aunque no es ideal. Cualquiera que sea el iterador que use, necesitará crear una instancia de value_type para return in operator *, incluso si lo descarta.

4

No es difícil escribir una.

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

No he probado esto, y probablemente falte algo importante, pero creo que esta es la idea.

+1

La idea es buena, pero no creo que necesite: T * operator ->() {return & m; } Y debe derivar de stl :: output_iterator Con esta implementación, se ejecuta una copia de T en cada asignación a través del iterador de salida. ¿Hay alguna manera de evitar eso? –

20

El STL no proporciona dicho iterador. Pero podría codificar usted mismo (probado que el código):

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

que no necesita ningún dato mediante el uso de sí mismo como el resultado de operator*. El resultado de *it = x; no se utiliza en los requisitos del iterador de salida, por lo que podemos darle un tipo de devolución de void.


Editar: Vamos a entrar en funcionamiento de esta operator* obras. El estándar dice en 24.1.2/1 acerca de los requisitos de un iterador de salida que en estos dos casos:

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

que el resultado de esas expresiones no se utiliza. Eso es lo que hace este trabajo:

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=`. 

ahora no necesita tener ningún dato que volvamos en operator*: Nos limitamos a usar el iterador en sí. Tenga en cuenta que el operador con plantilla = no sobrescribe el operador de asignación de copia integrado. Todavía se proporciona.

+0

¿Podría explicar mejor al operador *? –

+0

Se usa en combinación con el operador con plantilla =. Tricky, usaría una clase de ayuda anidada dev_null. Además, dejaría que el operador ++ (int) devuelva * esto inmediatamente. Esta versión es ineficiente. – MSalters

+0

msalters, la semántica operacional indica que se devuelve un nuevo objeto :) –

0

que la mina basado en std::back_insert_iterator, pero sin el contenedor:

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

Esto es similar a la respuesta de Johannes, pero sin la plantilla operator= que toma lo que sea. Me gusta escribir fuerte Quiero que *it = wrong_type_thing sea un error en tiempo de compilación. También esto usa void para los diversos parámetros de plantilla a std::iterator, como los iteradores de salida en la biblioteca estándar.

Esto también es similar a la solución de Mark, pero (a) hereda correctamente de std::iterator y (b) no tiene la variable de estado interna innecesaria.

Cuestiones relacionadas