Supongamos que tengo una estructura como esta:¿Se pueden usar plantillas para acceder a las variables de estructura por nombre?
struct my_struct
{
int a;
int b;
}
Tengo una función que debería establecer un nuevo valor para cualquiera de los dos "a" o "b". Esta función también requiere especificar qué variable establecer. Un ejemplo típico sería así:
void f(int which, my_struct* s, int new_value)
{
if(which == 0)
s->a = new_value;
else
s->b = new_value;
}
Por razones que no voy a escribir aquí no puede pasar el puntero para a/b para f. Por lo tanto, no puedo llamar a f con la dirección de my_struct :: a o my_struct :: b. Otra cosa que no puedo hacer es declarar un vector (int vars [2]) dentro de my_struct y pasar un entero como índice a f. Básicamente en f Necesito acceder a las variables por nombre.
El problema con el ejemplo anterior es que en el futuro planeo agregar más variables a struct y en ese caso recordaré agregar más sentencias if a f, lo cual es malo para la portabilidad. Una cosa que podría hacer es escribir f como una macro, como esto:
#define FUNC(which)
void f(my_struct* s, int new_value) \
{ \
s->which = new_value; \
}
y luego me podría llamar FUNC (a) o FUNC (b).
Esto funcionaría, pero no me gusta usar macros. Entonces mi pregunta es: ¿hay alguna manera de lograr el mismo objetivo usando plantillas en lugar de macros?
EDIT: Trataré de explicar por qué no puedo usar punteros y necesito acceder a la variable por nombre. Básicamente, la estructura contiene el estado de un sistema. Este sistema necesita "deshacer" su estado cuando se lo solicite. Deshacer se maneja mediante una interfaz llamada undo_token así:
class undo_token
{
public:
void undo(my_struct* s) = 0;
};
así que no puedo pasar punteros con el método de deshacer causa de polimorfismo (MyStruct contiene variables de otros tipos también).
Al agregar una nueva variable a la estructura I, también es posible añadir una nueva clase, así:
class undo_a : public undo_token
{
int new_value;
public:
undo_a(int new_value) { this->new_value = new_value; }
void undo(my_struct *s) { s->a = new_value}
};
El problema es que no sé puntero a s cuando se crea el token, por lo que no puede guarde un puntero a s :: a en el constructor (que habría resuelto el problema). La clase para "b" es la misma, solo tengo que escribir "s-> b" en lugar de s-> a
Quizás esto sea un problema de diseño: Necesito un token de deshacer por tipo de variable, no uno por variable ...
FUNC (a) - definirá f (s, new_value). ¿Pero cómo lo llamarás entonces? –
Sí, lo siento, fue un error. Pero espero que entiendas el punto de todos modos :) – Emiliano
Incluso después de tu edición, utilizando mi respuesta y la de Mykola Golubyev, aún puedes parametrizar tu clase deshacer con un puntero a un miembro de datos de clase y vincularla a la clase/estructura al invocar miembros hora. – camh