ver - C++, ¿puedo inicializar estáticamente un std:: map en tiempo de compilación?
imagenes de google earth (8)
Con C ++ 0x, es posible que necesite utilizar llaves todo el camino (también use la sintaxis de estilo nuevo para cada par):
std::map<int, char> example = { {1,''a''}, {2, ''b''}, {3, ''c''} };
Esos paréntesis para construir pares no son significativos. Alternativamente, puede nombrar por completo cada par o usar make_pair (como lo haría en C ++ 98)
std::map<int, char> example = {
std::make_pair(1,''a''),
std::make_pair(2, ''b''),
std::make_pair(3, ''c'')
};
En cuanto a la creación de esas instancias en tiempo de compilación: no. Los contenedores STL encapsulan por completo la gestión de la memoria de tiempo de ejecución.
Supongo que realmente solo tienes un mapa en tiempo de compilación con bibliotecas como la metaprogramación de boost (no está 100% seguro, si es completamente correcto, y no has estudiado para qué podría servir):
using namespace boost::mpl;
map<
pair<integral_c<int, 1>, integral_c<char, ''a''> >,
pair<integral_c<int, 2>, integral_c<char, ''b''> >,
pair<integral_c<int, 3>, integral_c<char, ''c''> >
> compile_time_map;
Si codigo esto
std::map<int, char> example = {
(1, ''a''),
(2, ''b''),
(3, ''c'')
};
entonces g ++ me dice
deducing from brace-enclosed initializer list requires #include <initializer_list>
in C++98 ‘example’ must be initialized by constructor, not by ‘{...}’
y eso me molesta un poco porque el constructor está en tiempo de ejecución y puede, en teoría, fallar.
Claro, si lo hace, fallará rápidamente y debería hacerlo constantemente, de modo que debería localizar y corregir rápidamente el problema.
Pero, aún así, tengo curiosidad: ¿hay alguna forma de inicializar mapa, vector, etc. en tiempo de compilación?
Editar: Debería haber dicho que estoy desarrollando sistemas embebidos. No todos los procesadores tendrán un compilador C ++ 0x. El más popular probablemente lo hará, pero no quiero encontrar un gotcha y tengo que mantener 2 versiones del código.
En cuanto a Boost, estoy indeciso. Son poco sólidos en cuanto al uso de sus clases de Máquina de estados finitos en sistemas integrados, de modo que eso es en realidad lo que estoy codificando aquí, las clases Event / State / Fsm.
Suspiro, supongo que será mejor que vaya a lo seguro, pero espero que esta discusión haya sido útil para otros.
Con pre-C ++ 0x, lo más cercano que puede obtener es no usar contenedores diseñados para uso en tiempo de ejecución (y limitándose a tipos y agregados fundamentales) :
struct pair { int first; char second; };
pair arr[] = {{1,''a''}, {2,''b''}}; // assuming arr has static storage
A continuación, se podría acceder utilizando algún tipo de vista de mapa , o podría implementar un contenedor que permita la inicialización agregada similar a lo que hace Boost.Array .
Por supuesto, la pregunta es si los beneficios justifican el tiempo invertido en implementar esto.
Si mi lectura es correcta aquí, C ++ 0x initializer-lists puede darle inicialización estática de no agregados como std::map
y std::pair
, pero solo si eso no cambia la semántica en comparación con la inicialización dinámica.
Por lo tanto, me parece que solo puede obtener lo que solicitó si su implementación puede verificar mediante análisis estático que el comportamiento no cambia si el map
está inicializado estáticamente, pero no hay garantías de que ocurra.
Hay un truco que puedes usar, pero solo si estos datos no se usarán en ningún otro constructor estático. Primero defina una clase simple como esta:
typedef void (*VoidFunc)();
class Initializer
{
public:
Initializer(const VoidFunc& pF)
{
pF();
}
};
Entonces, úsalo así:
std::map<std::string, int> numbers;
void __initNumsFunc()
{
numbers["one"] = 1;
numbers["two"] = 2;
numbers["three"] = 3;
}
Initializer __initNums(&__initNumsFunc);
Por supuesto, esto es un poco exagerado, así que recomendaría usarlo solo si realmente es necesario.
No en C ++ 98. C ++ 11 es compatible con esto, por lo que si habilita las banderas de C ++ 11 e incluye lo que sugiere g ++, puede hacerlo.
Editar: desde gcc 5 C ++ 11 está activado por defecto
No es exactamente la inicialización estática, pero aún así, pruébalo. Si su compilador no es compatible con C ++ 0x, iría por el constructor de iteraciones de std :: map:
std::pair<int, std::string> map_data[] = {
std::make_pair(1, "a"),
std::make_pair(2, "b"),
std::make_pair(3, "c")
};
std::map<int, std::string> my_map(map_data,
map_data + sizeof map_data / sizeof map_data[0]);
Esto es bastante legible, no requiere bibliotecas adicionales y debería funcionar en todos los compiladores.
No hay una forma estándar de inicializar std::map
en tiempo de compilación. Como otros han mencionado, C ++ 0x permitirá que el compilador optimice la inicialización para que sea estática si es posible, pero eso nunca será garantizado.
Recuerde, sin embargo, que el STL es solo una especificación de interfaz. Puede crear sus propios contenedores compatibles y darles capacidad de inicialización estática.
Dependiendo de si planea actualizar su compilador y la implementación de STL (particularmente en una plataforma incrustada), ¡puede incluso profundizar en la implementación que está utilizando, agregar clases derivadas y usarlas!
Puede usar la biblioteca Boost.Assign :
#include <boost/assign.hpp>
#include <map>
int main()
{
std::map<int, char> example =
boost::assign::map_list_of(1, ''a'') (2, ''b'') (3, ''c'');
}
Sin embargo, como señalaron Neil y otros en los comentarios a continuación, esta inicialización ocurre en tiempo de ejecución, de forma similar a la propuesta de UncleBean.
template <const int N> struct Map { enum { value = N}; };
template <> struct Map <1> { enum { value = (int)''a''}; };
template <> struct Map <2> { enum { value = (int)''b''}; };
template <> struct Map <3> { enum { value = (int)''c''}; };
std::cout << Map<1>::value ;