2010-02-18 15 views
6

Imaginemos que quiero hacer una función de plantilla que devuelva el primer elemento de cualquier contenedor stl. La manera general sería:¿Cómo probar si el parámetro de plantilla es un contenedor asociativo de par?

template<typename Container> 
Container::value_type first(Container c){ 
    return *(c.begin()); 
} 

Esto funciona para vectores, listas, deques, conjuntos y así sucesivamente.

Sin embargo, para los envases par asociativos (std :: mapa), si les gustaría tener

return c.begin()->second; 

¿Cómo podría probar (en la función o con la especialización de plantilla) si tengo un contenedor asociativo par?

El contenedor STL parece no tener ningún rasgo asociado. ¿Es posible verificar si tiene un :: key_type?

Respuesta

3

Usted puede hacer con bastante facilidad:

namespace result_of // pillaged from Boost ;) 
{ 
    template <class Value> 
    struct extract { typedef Value type; }; 

    template <class First, class Second> 
    struct extract < std::pair<First,Second> > { typedef Second type; }; 
} 

template <class Value> 
Value extract(Value v) { return v; } 

template <class First, class Second> 
Second extract(std::pair<First,Second> pair) { return pair.second; } 

template <class Container> 
typename result_of::extract< typename Container::value_type >::type 
first(const Container& c) { return extract(*c.begin()); } 

Debo señalar sin embargo, que, probablemente, me gustaría añadir una prueba para ver si el recipiente es empty ... Porque si el recipiente es empty, estás en para un comportamiento indefinido

En movimiento:

int main(int argc, char* argv[]) 
{ 
    std::vector<int> vec(1, 42); 
    std::map<int,int> m; m[0] = 43; 
    std::cout << first(vec) << " " << first(m) << std::endl; 
} 

// outputs 
// 42 43 

Ejemplo descaradamente tomado de litb;)

+0

Nice answer. Para que compile, ';' faltan al final de las estructuras y .front() no funciona para todo –

+0

Oups, que lo que obtiene al responder demasiado rápido: he agregado el ';' perdido y reemplazado 'frontal' por un sin referencia 'comenzar' :) –

3

Esta funciona:

template<typename T> 
struct tovoid { 
    typedef void type; 
}; 

template<typename T, typename = void> 
struct value_type { 
    typedef typename T::value_type type; 
    static type get(T const& t) { 
    return *t.begin(); 
    } 
}; 

template<typename T> 
struct value_type<T, typename tovoid<typename T::mapped_type>::type> { 
    typedef typename T::mapped_type type; 
    static type get(T const& t) { 
    return t.begin()->second; 
    } 
}; 

template<typename Container> 
typename value_type<Container>::type first(Container const& c){ 
    return value_type<Container>::get(c); 
} 

int main() { 
    std::map<int, int> m; m[0] = 42; std::cout << first(m); 
    std::vector<int> a(1, 43); std::cout << first(a); 
} 

(salidas 4243)

1

Uso especialización de función de plantilla:

template<typename Container> 
typename Container::value_type first(typename Container c) 
{ 
    return *(c.begin()); 
} 


template<typename K, typename V> 
typename V first(std::map<K,V> & c) 
{ 
    return c.begin()->second; 
} 
Cuestiones relacionadas