tipos template programacion plantillas plantilla manejo example con arreglos ambiente c++ templates methods stdmap

template - C++ std:: mapa de valores de clase de plantilla



template<> c++ (3)

  1. Aquí tienes un error: tienes que "valorar" al miembro en el campo (probablemente uno debería ser "tipo").
  2. Por favor, no mantenga punteros crudos en el valor del mapa. Utilice boost :: shared_ptr .
  3. Además, debe tener una buena razón para escribir estas clases donde ya hay muchos códigos de manejo de BD / tablas que probablemente pueda usar. Entonces, si es aplicable, considere usar algo existente y no escribir su propio código de manejo de tabla.

Ahora, para responder a su pregunta :), las clases Field <> pueden heredar de una clase base común compartida por todos los tipos de datos. De esta forma, un contenedor como el mapa de columnas puede mantener los punteros (hacer que los punteros compartidos ) a los objetos derivados que se instancian de una clase de plantilla.

Estoy intentando declarar una Row y una clase de Column , con la Row tiene un private std::map con valores que apuntan a una Column plantilla. Algo como esto:

template <typename T> class DataType { private: T type; }; template <typename T> class Field { private: T value; DataType<T> value; }; class Row { private: std::map<unsigned long,Field*> column; };

Bueno, supongo que en principio la clase Row no debería tener que saber qué tipo de Field (o Column ) nos gustaría usar, es decir, si es un Field<int> en la columna 1 o un Field<double> en la columna 2 Pero no estoy seguro de cuál es la sintaxis correcta para la declaración de Row::column , o si std::map está limitado en este sentido y debería estar usando algo más.

Aplaudo tus sugerencias y gracias por ellas de antemano.


Field solo no es un tipo, sino una plantilla que puede generar una familia de tipos, como Field<int> y Field<double> . Todos estos campos no están relacionados de modo que uno se deriva de alguna manera del otro o tal. Entonces debes establecer alguna relación entre todos estos tipos generados. Una forma es usar una clase base común que no sea una plantilla:

class FieldBase { }; template <typename T> class Field : public FieldBase { private: T value; DataType<T> type; }; class Row { private: std::map<unsigned long,FieldBase*> column; };

Y considere usar un puntero inteligente en lugar de ese puntero sin formato en el código. De todos modos, ahora el problema es que la información de tipo se pierde, ya sea que apunte a un Field<double> o a un Field<int> ya no se conoce y solo se puede detectar manteniendo algún tipo de indicador de tipo en la base que es establecido por la clase derivada de plantilla - o preguntando a RTTI usando

dynamic_cast<Field<int>*>(field) != 0

Pero eso es feo Especialmente porque lo que quieres allí es un valor semántico. Es decir, desearía poder copiar su fila y copiaría todos los campos en ella. Y desea obtener un doble cuando se almacena un doble, sin usar RTTI primero para abrirse camino hacia el tipo derivado.

Una forma de hacerlo es usar una unión discriminada. Eso es básicamente una unión para algunos tipos arbitrarios y, además, un indicador de tipo, que almacena qué valor se almacena actualmente en ese campo (por ejemplo, si es un doble, int, ...). Por ejemplo:

template <typename T> class Field { private: T value; DataType<T> type; }; class Row { private: std::map<unsigned long, boost::variant< Field<int>, Field<double> > > column; };

boost :: variant hace todo el trabajo por ti. Puede usar las visitas para hacer que se llame a un functor utilizando la sobrecarga correcta. Eche un vistazo a su manual


Una Row< int, float, int> es realmente diferente de una Row<int, std::string> . Claramente, Row<int,float,int>.field<0> debe ser un Field<int> mientras que Row<int,float,int>.field<1> debe ser un Field<float> . Y Row<int,float,int>.field<3> es un error del compilador.

La forma más fácil de hacerlo es usar Boost. Una gran parte de la inteligencia fue iniciada por Loki (ver Diseño Moderno en C ++ , por Andrei Alexandrescu ) pero Boost es más moderno y está mejor respaldado.

Normalmente, no iteraría sobre los campos; cada campo tiene su propio tipo. Pero de ti, de hecho, necesitarías un FieldBase . Si necesita una interfaz así, probablemente también valga la pena almacenar los campos internamente como boost::array<FieldBase, N> (es decir, Row<int,float,int> tiene un boost::array<FieldBase, 3> ). FieldBase* embargo, nunca debería necesitar dynamic_cast FieldBase* . Esa es una prueba de tiempo de ejecución, y siempre se conoce la T exacta de cada Field<T> en el momento de la compilación.