viniendo de un fondo principalmente de Python, he tenido dificultades para trabajar con tipos en C ++.
Estoy intentando inicializar una variable de clase a través de uno de varios constructores sobrecargados que toman diferentes tipos como parámetros. He leído que usar la autopalabra clave se puede usar para la declaración automática de una variable, sin embargo, en mi caso, no se inicializará hasta que se elija un constructor. Sin embargo, el compilador no está contento con no inicializar value.
class Token {
public:
auto value;
Token(int ivalue) {
value = ivalue;
}
Token(float fvalue) {
value = fvalue;
}
Token(std::string svalue) {
value = svalue;
}
void printValue() {
std::cout << "The token value is: " << value << std::endl;
}
};
En python esto podría verse así:
class Token():
def __init__(self, value):
self.value = value
def printValue(self):
print("The token value is: %s" % self.value)
¿Cuál es la forma correcta de usar la autopalabra clave en este escenario? ¿Debo usar un enfoque completamente diferente?

autopara los miembros de la clase? Pregunta relevante pero desactualizada: ¿Es posible tener una variable miembro "auto"?Respuestas:
No existe tal cosa como "variable de tipo desconocido" en C ++.
Las variables auto deducidas tienen un tipo que se deduce del inicializador. Si no hay inicializador, no puede usar auto. auto no se puede usar para una variable miembro no estática. Una instancia de una clase no puede tener miembros con un tipo diferente que otra instancia.
No hay forma de usar la palabra clave automática en este escenario.
Probablemente. Parece que estás intentando implementar a
std::variant. Si necesita una variable para almacenar uno de X número de tipos, eso es lo que debe usar.Sin embargo, puede estar tratando de emular la escritura dinámica en C ++. Si bien puede ser familiar para usted debido a la experiencia con Python, en muchos casos ese no es el enfoque ideal. Por ejemplo, en este programa de ejemplo en particular, todo lo que hace con la variable miembro es imprimirlo. Por lo tanto, sería más sencillo almacenar una cadena en cada caso. Otros enfoques son el polimorfismo estático como lo muestra Rhathin o el polimorfismo dinámico de estilo OOP como lo muestra Fire Lancer.
fuente
uniones un mecanismo de bajo nivel propenso a errores.variantprobablemente lo usa internamente y hace que su uso sea más seguro.varianthace usounion. La alternativa, usando memoria en bruto y ubicación nueva, no puede usarse en unconstexprconstructor.C ++ es un lenguaje de tipo estático , lo que significa que todos los tipos de variables se determinan antes del tiempo de ejecución. Por lo tanto, la
autopalabra clave no es algo así como lavarpalabra clave en javascript, que es un lenguaje de tipo dinámico.autoLa palabra clave se usa comúnmente para especificar tipos que son innecesariamente complejos.Lo que está buscando podría hacerse utilizando la clase de plantilla C ++, que permite crear múltiples versiones de la clase que toman diferentes tipos.
Este código puede ser la respuesta que estás buscando.
Este código se compilaría si se cumplen algunas condiciones, como la función
operator<<debería definirse para std :: ostream & y type T.fuente
Un enfoque diferente, de lo que otros han propuesto, es usar plantillas. Aquí hay un ejemplo:
Entonces puedes usar tu clase así:
fuente
Puedes usar el
std::varianttipo. El siguiente código muestra una forma (pero debo admitir que es un poco torpe):Sería mucho mejor si se
std::get<0>(value)pudiera escribir comostd::get<value.index()>(value)pero, por desgracia, la "x"<x>debe ser una expresión constante en tiempo de compilación.fuente
std::visitlugar deswitch.autodebe ser deducible a un tipo específico, no proporciona escritura dinámica en tiempo de ejecución.Si al momento de declarar
Tokenconoce todos los tipos posibles que puede usar,std::variant<Type1, Type2, Type3>etc. Esto es similar a tener una "enumeración de tipos" y una "unión". Se asegura de que se llame a los constructores y destructores adecuados.Una alternativa podría ser crear un
Tokensubtipo diferente para cada caso (posiblemente usando plantillas) con métodos virtuales adecuados.fuente
La solución a continuación es similar en espíritu a la respuesta de Fire Lancer. Su diferencia clave es que sigue el comentario posiblemente usando plantillas , y así elimina la necesidad de crear instancias derivadas creadas explícitamente de la interfaz.
Tokenno es en sí la clase de interfaz. En cambio, define la interfaz como una clase interna y una clase de plantilla interna para automatizar la definición de las clases derivadas.Su definición parece demasiado compleja. Sin embargo,
Token::Basedefine la interfaz yToken::Impl<>deriva de la interfaz. Estas clases internas están completamente ocultas para el usuario deToken. El uso se vería así:Además, la solución a continuación ilustra cómo se podría implementar un operador de conversión para asignar una
Tokeninstancia a una variable regular. Se basadynamic_casty arrojará una excepción si el lanzamiento no es válido.La definición de
Tokenestá abajo.Pruébalo en línea!
fuente