2011-09-26 22 views
5

¿Cómo escribo una función de plantilla que opera en un contenedor arbitrario de un tipo arbitrario? Por ejemplo, ¿cómo puedo generalizar esta función ficticiaPlantilla de plantilla C++ Función

template <typename Element> 
void print_size(const std::vector<Element> & a) 
{ 
    cout << a.size() << endl; 
} 

a

template <template<typename> class Container, typename Element> 
void print_size(const Container<Element> & a) 
{ 
    cout << a.size() << endl; 
} 

Aquí es un uso típico

std::vector<std::string> f; 
print_size(f) 

Esto da error

tests/t_distances.cpp:110:12: error: no matching function for call to ‘print(std::vector<std::basic_string<char> >&)’. I'm guessing I must tell the compiler something more specific about what types that are allowed. 

¿Qué es esta variante del uso de plantilla y cómo puedo solucionarlo?

Respuesta

13

¿Hay alguna razón específica para utilizar una plantilla de plantilla? ¿Por qué no solo así?

template <typename Container> 
void print_size(Container const& a) 
{ 
    cout << a.size() << endl; 
} 

En general, las plantillas de plantilla no valen la pena. En su caso particular, ciertamente no sirve de nada, y si realmente necesita acceder al tipo de miembro, le sugiero que se doblegue a la práctica común y use una metafunción (typename Container::value_type en este caso).

+0

¿Qué sucede si necesita obtener el tipo "contenido"? Por ejemplo, si desea crear una función que le proporcione un std :: map de dos std :: vector (uno para las claves, el otro para los valores). Pero podría usar algo más que std :: vector como una clase personalizada con iteradores begin() y end(). – ibizaman

+0

@ibizaman Para eso son typendefs. Simplemente use 'typename Container :: value_type' (tenga en cuenta el prefijo' typename', es importante, hay otras preguntas que explican por qué). –

+0

es este estándar value_type? Bueno, sé que está en stl para std :: vector, pero ¿es la forma reconocida de hacerlo para clases personalizadas? – ibizaman

1

Por qué ha consumido alguna vez algo así como

template <template<typename> class Container, typename Element> 
void print_size(const Container<Element> & a) 
{ 
    cout << a.size() << endl; 
} 

? Usarlo en forma más simple:

template<typename Container> 
void print_size(const Container & a) 
{ 
    cout << a.size() << endl; 
} 

Al llamar print_size(f), se le llame print_size con Container siendo vector<string>.

3

El problema es que la plantilla vector toma dos argumentos de tipo, y la plantilla solo acepta argumentos de plantilla que aceptan un único argumento. La solución más simple es el levantamiento de un poco de la seguridad de tipos y simplemente usando Container como un tipo:

template <typename Container> 
void print_size(Container const & c) { 
    std::cout << c.size() << std::endl; 
} 

Posiblemente la adición de controles estáticos (sea cual sea el tipo Container es, tiene que tener un tipo anidado value_type que es Element ...) La alternativa sería hacer que el argumento de plantilla de plantilla coincida con las plantillas que se aprobarán (incluido el asignador para secuencias, asignador y predicado de orden para contenedores asociativos) ...

0

Para estos tipos de algoritmos genéricos, I siempre prefieren iteradores, es decir

template <typename IteratorType> 
void print_size(IteratorType begin, IteratorType end) { 
    std::cout << std::distance(begin, end) << std::endl; 
} 

Para llamar:

std::vector<std::string> f; 
print_size(f.begin(), f.end()); 
+0

¿Por qué preferirías esto, especialmente teniendo en cuenta que 'distancia 'puede tener una complejidad algorítmica peor que la función de miembro' tamaño'? – UncleBens

+0

@UncleBens - sí - eso es cierto para los iteradores de acceso no aleatorio, en este caso, no debería haber diferencia. De todos modos, este ejemplo es trivial, lo que quiero decir es que (la mayoría) de los algoritmos estándar de la biblioteca funcionan con iteradores, entonces ¿por qué no hacer tus algoritmos de la misma manera? – Nim

2

sé que la pregunta fue hecha hace mucho tiempo, pero que tenía el mismo problema, y ​​la solución es que usted necesita para escribir

template <template <typename,typename> class Container, typename element, typename Allocator> 
void print_size(Container<element, Allocator> & a) 
{ 
    std::cout << a.size() << std::endl; 
} 

porque el vector tiene dos parámetros de plantilla

Cuestiones relacionadas