2012-09-19 53 views
6

Estoy usando funciones de plantilla para la construcción de objetos para crear objetos a partir de datos de reflexión, y funciona bastante bien, pero ahora quiero admitir tipos de contenedor STL en el sistema de reflexión para objetos como:C++ Get Vector type

// Note - test case only 
// for real world usage it would probably not be structured like this 
// and the phrases would be mapped by an id or something 
struct Phrases { 
    std::vector<std::string> phrases; 
}; 

typedef std::string Lang; 
struct Langs { 
    std::map< Lang, Phrases > translations; 
}; 

Puede ser compatible. Puedo hacer un poco de magia de expresiones regulares en el retorno de

typeid(object).name() 

de averiguar si un objeto es un vector o un mapa, y cuáles son los argumentos de los parámetros para el objeto. Y he intentado utilizar magia de plantilla para hacer algo como lo siguiente, donde CreateString, ConstructString & DestroyString están en funciones y los datos se incluyen también para algo un poco más complejo que utiliza una base de datos tipo para manejar la construcción de objetos.

// Representational of code, basically a copy-paste to a different test project where I can work out the problems with this specific vector problem 
// Vector specialised construction 
template <typename T> void ConstructVector(void* object, const std::vector<std::string>& data) { 
    T* vec = (T*)object; 
    Name vector_type = GetVectorTypeName<T>(); 

    void *obj; 
    CreateString(&obj); 
    // All fields in this type should be valid objects for this vector 
    for(std::vector<std::string>::const_iterator it = data.begin(), end = data.end(); it != end; ++it) { 
    // Push it 
    vec->push_back(*obj); 
    // Get address to new instance 
    void *newly = &vec->back(); 
    ConstructString(newly,*it); 
    } 
    DestroyString(&obj); 

} 

que no funciona debido a la indirección ilegal con "Vec-> push_back (* obj);" lo cual no puedo explicar porque en realidad no conozco el tipo. Básicamente, lo que necesito hacer es crear este vector con algunos elementos sin unir en blanco, o agregarle nuevos elementos sin tener realmente el tipo, porque si puedo obtener un puntero a un bloque de memoria dentro del vector, puedo rodar con eso y construir el objeto. Pero el vector añadir requisitos tales como

vector::push_back(T& value) 

o

vector::insert(Iter&, T&) 

no me va a funcionar a menos que esté en mis manos en ese tipo T desde el interior de la plantilla

Pastebin de código de prueba para tratar de resolver esto: http://pastebin.com/1ZAw1VXg

Así que mi pregunta es, ¿cómo puedo obtener la std :: string parte de una declaración std :: vector cuando estoy dentro de una plantilla como

template <typename T> void SomeFunc() { 

    // Need to get std::string here somehow  
    // Alternatively need to make the vector a certain size and then 
    // get pointers to it's members so I can construct them 
} 


SomeFunc<std::vector<std::string>>>(); 
+1

El 'std :: vECTOR' tiene un 'typedef T value_type' interno si eso es lo que necesita. –

Respuesta

15

Hay dos formas de lograr esto.

1) O se hacen uso del hecho de que std::vector<> (como todas las clases de contenedor biblioteca estándar) mantiene un tipo de miembro value_type, que representa el tipo de los elementos almacenados en el vector. Así que usted puede hacer esto:

template <typename T> void SomeFunc() { 
    typename T::value_type s; // <--- declares a `std::string` object 
          //  if `T` is a `std::vector<std::string>` 
} 

2) O de lo contrario, se cambia la declaración de su función y hacer uso de los parámetros de plantilla de la plantilla:

template <template <typename> class T, typename Elem> 
void SomeFunc(T<Elem> &arg) 
{ 
    Elem s; 
} 

Sin embargo, hay un pequeño problema eso: std::vector es realmente una plantilla con dos parámetros (tipo de elemento y tipo de asignador), lo que hace que sea un poco difícil usar los parámetros de plantilla de plantilla y aún así mantener la sintaxis simple.Una cosa que trabajó para mí es declarar un alias del tipo de vector de parámetros que deja sólo una plantilla:

template <typename Elem> 
using myvector = std::vector<Elem>; 

entonces puedo usar SomeFunc así:

int main() 
{ 
    myvec<std::string> vec; 
    SomeFunc(vec); 
} 
+0

Gracias por eso, me permitirá hacer una versión mucho más limpia de la función que la solución que he pirateado. – kyall