2012-05-25 8 views
6

Quiero tener una interfaz ModelGenerator que tenga un método generate() que tome una lista iterativa de Evidencia y cree un Modelo. Utilizando el STL pseudo-pato-tipificación iterador idioma ...Método virtual C++ que toma iteradores de estilo STL

template<class Model> 
class ModelGenerator { 
    public: 
    template<class Iterator> 
    virtual bool generate(Iterator begin, Iterator end, Model& model) = 0; 
}; 

Pero las funciones virtuales no pueden ser con plantilla. Así que tengo a la plantilla de la clase entera:

template<class Model, class Iterator> 
class ModelGenerator { 
    public: 
    virtual bool generate(Iterator begin, Iterator end, Model& model) = 0; 
}; 

Lo ideal sería que lo que me gustaría hacer es algo como esto ...

template<class Model, class Evidence> 
class ModelGenerator { 
    public: 
    virtual bool generate(iterator<Evidence>& begin, 
          iterator<Evidence>& end, 
          Model& model) = 0; 
}; 

Pero no hay tal interfaz que heredan de iteradores. (La clase std :: iterator solo contiene un montón de typedefs, no hay métodos.)

La única forma en que puedo pensar en hacerlo es darle a ModelGenerator un método addEvidence() que los agrega uno por uno antes de llamar a generate (), pero luego tengo que darle al estado ModelGenerator un poco de dolor.

¿Cómo puedo escribir un método virtual que tome cualquier contenedor STL?

+1

CRTP podría ser útil aquí. – Mehrdad

+2

Debería considerar factorizar todas las operaciones del iterador desde la función virtual. La función de plantilla podría generar un 'std :: vector ' y pasarlo a la función 'virtual'. El costo de rendimiento y el esfuerzo de programación de ese tipo de contenedor es probable que sea menor que 'any_iterator' /' any_range'. – Potatoswatter

Respuesta

5

Parece que necesita un any_iterator. Es un iterador que realiza borrado de tipo para aislarlo de la implementación real del iterador.

Adobe tiene una implementación de any_iterator: http://stlab.adobe.com/classadobe_1_1any__iterator.html

Boost tiene una implementación de any_range: http://www.boost.org/doc/libs/1_49_0/libs/range/doc/html/range/reference/ranges/any_range.html

+0

¡Gracias! ¿Sabes si se encuentra any_iterator en alguna de las principales bibliotecas? –

+1

Tenga en cuenta que las implementaciones de 'any_iterator' son lentas, así que solo uselas cuando sea necesario. –

+0

@funkybluecoffee: Not Boost, desafortunadamente. Adobe tiene uno: http://stlab.adobe.com/classadobe_1_1any__iterator.html –

0

Se podría considerar la utilización de especialización de plantilla en lugar de métodos virtuales para este fin. Por lo que entiendo, tiene una clase de Evidencia única, una serie de clases de Modelos distintas y un objetivo para crear una fábrica genérica para producir un Modelo seleccionado a partir de una secuencia de Evidencias.

#include <vector> 
#include <iostream> 

struct Model1 { }; 
struct Model2 { }; 
struct Evidence { }; 

template<class Model> 
struct ModelGenerator; 

template<> 
struct ModelGenerator<Model1> 
{ 
    typedef Model1 model_type; 

    template<class Iterator> 
    model_type generate(Iterator begin, Iterator end) 
    { 
     std::cout << "Generate Model1\n"; 
     return model_type(); 
    } 
}; 

template<> 
struct ModelGenerator<Model2> 
{ 
    typedef Model2 model_type; 

    template<class Iterator> 
    model_type generate(Iterator begin, Iterator end) 
    { 
     std::cout << "Generate Model2\n"; 
     return model_type(); 
    } 
}; 

template<class Model, class Iterator> 
Model make_model(Iterator begin, Iterator end) 
{ 
    ModelGenerator<Model> gen; 
    return gen.generate(begin, end); 
} 

Se puede utilizar de esta manera:

int main() 
{ 
    std::vector<Evidence> v; 

    Model1 m1 = make_model<Model1>(v.begin(), v.end()); 
    Model2 m2 = make_model<Model2>(v.begin(), v.end()); 
} 
Cuestiones relacionadas