2010-06-10 12 views
15

Es fácil dar un recipiente para obtener los iteradores asociados, ejemplo:Obtener tipo de contenedor a partir de (su) Tipo de iterador en C++ (STL)

std::vector<double>::iterator i; //An iterator to a std::vector<double> 

Me preguntaba si es posible, dado un tipo iterador , para deducir el tipo del "contenedor correspondiente" (aquí supongo que para cada contenedor hay uno y solo un iterador (no const)).

Más precisamente, me gustaría un metafunción plantilla que funciona con todos los contenedores STL (sin tener que especializarse manualmente para cada contenedor individual) de tal manera que, por ejemplo:

ContainerOf< std::vector<double>::iterator >::type 

evalúa a

std::vector<double> 

¿Es posible? Si no, ¿por qué?

Gracias de antemano por cualquier ayuda!

+2

¿Estás tratando de averiguar sobre el Concep de un iterador ? es decir, si es de acceso aleatorio? El STL usa etiquetas para esto. Por lo general, no hay ninguna razón para saber de dónde viene un iterador. – pmr

+0

¿Sabe de antemano si tiene un iterador en uno de los 7 contenedores STL, o necesita una cláusula "else" también? – MSalters

Respuesta

7

No creo que esto sea posible. En algunas bibliotecas STL, en realidad tiene un iterador vectorial como tipo de puntero, i.e. std::vector<T>::iterator is a T*, así que no puedo pensar en ninguna manera de poder regresar al tipo de contenedor.

+0

Sin embargo, este no puede ser el iterador de ningún otro contenedor STL. Solo hay 7, y podrías emanciparlos a todos. – MSalters

+0

Ese es un punto justo. ¿Qué hay de la diferencia entre map y multimap? ¿Puedes distinguirlos del operador de comparación? – Hitobat

+0

Podría ser posible si la estructura 'std :: iterator_traits ' haves 'typedef T container_type;' sin embargo puede hacer su propio 'std :: iterator_traits_pro' con such typedef. – k06a

0

Los tipos de tiempo de ejecución exactos de los iteradores C++ STL están intencionalmente indefinidos y, por lo tanto, específicos de la implementación. Puede buscar a través de los archivos de encabezado de su proveedor de compilación para averiguar qué tipo se utiliza realmente y deducir el contenedor de eso, pero es específico del proveedor y la versión, por lo tanto, propenso a romperse.

+0

¡Gracias por la respuesta! Ahora estoy seguro de que mi problema intencionalmente no es "solucionable". – stepelu

0

El punto de los iteradores es que los usa para hacer el trabajo sin tener que conocer el tipo de contenedor subyacente, por ejemplo, pasando un par de inicio/final y trabajando en ese rango.

Sin embargo, si todo lo que le interesa es el tipo de iterador, creo que puede usar rasgos de iterador para determinar, por ejemplo, si un iterador tiene acceso aleatorio. Tome std::advance, el caso general es que llama al operator++ en el iterador n veces, pero está especializado para que los iteradores de acceso aleatorio usen + = en su lugar.

Aparte de eso, no conozco ninguna forma de obtener el tipo de contenedor del iterador.

+0

Esto se logra mediante el despacho de etiquetas. http://www.boost.org/community/generic_programming.html#tag_dispatching –

5

Sólo por diversión, aquí hay algo que rápidamente hackeado con Boost.MPL (advertencia: Este era muuuy superficialmente a prueba, lo que debe manipularse con cuidado):

#include <boost/mpl/list.hpp> 
#include <boost/mpl/find_if.hpp> 
#include <boost/type_traits.hpp> 
#include <vector> 
#include <string> 
#include <list> 
#include <set> 

// List of candidate container types 
template<typename T> 
struct ContainersOf : boost::mpl::list< 
    std::vector<T>, 
    std::basic_string<T>, 
    std::list<T>, 
    std::set<T> 
>{}; 

// Metafunction to evaluate if IteratorT == ContainerT::iterator 
template<class IteratorT, class ContainerT> 
struct IsIteratorOf 
{ 
    typedef typename 
    boost::is_same< 
     IteratorT, 
     typename ContainerT::iterator 
    >::type type; 
}; 

// Metafunction to compute a container type from an iterator type 
template<class IteratorT> 
struct ContainerOf 
{ 
    typedef typename 
    boost::mpl::deref<typename 
     boost::mpl::find_if< 
      ContainersOf<typename std::iterator_traits<IteratorT>::value_type>, 
      IsIteratorOf<IteratorT, boost::mpl::_1> 
     >::type 
    >::type type; 
}; 

// Test 
int main() 
{ 
    ContainerOf<std::list<int>::iterator>::type l; 
    std::list<int> l2 = l; // OK 
    std::vector<int> v = l; // Fails to compile 

    return 0; 
} 
+0

Muchas gracias por su respuesta; sin embargo, su solución requiere "especialización" para los tipos de contenedores, consulte ContainerOf. – stepelu

Cuestiones relacionadas