¿Cómo comprobar el tipo de datos en C ++?

Soy bastante nuevo en C ++, he estado usando python principalmente. Estoy tratando de verificar el tipo de variable del valor almacenado en los objetos en los que estoy trabajando. Recuerdo que en Python había una isinstance donde podía usarla como una condición para ejecutar ciertos comandos, como si el siguiente valor es una cadena, haz A y si es una int do B.

¿Hay alguna forma de verificar rápidamente cuál es el tipo de datos en una variable en C ++?

Ejemplo:

En Python tenía una matriz con una operación matemática, cada personaje en un campo

 [3,"+",2] 

al leer la matriz, separaría las entradas de las cadenas con el comando isinstance

 if isinstance(list[0],int): aux1.append(list[0]) list=list[1:] else: if isinstance(lista[0],str): aux2.append(list[0 list=list[1:] 

ahora en C ++ necesito hacer algo similar, pero esta vez cada personaje está en un nodo de una lista vinculada y nuevamente, necesito separarlos, ints en una lista vinculada y cadenas en otra lista vinculada

Con lo que parece estar luchando es que C ++ es un lenguaje estático y (relativamente) fuertemente tipado. Para una discusión sobre el significado de cada uno de estos términos, me refiero a esta otra pregunta , ya que se explica que probablemente sea mucho mejor de lo que podría.

En primer lugar, debe asegurarse de que realmente necesita hacer las cosas como lo está haciendo actualmente. No intente escribir código de estilo de Python.

Dicho esto, hay básicamente dos enfoques diferentes con los que puede lograr un comportamiento similar al que Python (tipografía dinámica, tipificación de pato y, por lo tanto, tipificación relativamente débil) le permite hacer:

  1. Utilice los mecanismos de tipo dynamic incorporados de C ++. Por lo tanto, debe crear una llamada clase polimórfica base , que es una clase que tiene al menos una función miembro virtual (el destructor también funciona si no tiene una interfaz definida; la mayoría de las veces también debe ser virtual para evitar desagradables cuestiones). Un breve ejemplo:

     struct Value { virtual void write_to(std::ostream &) const = 0; virtual void read_from(std::istream &) = 0; virtual ~Value() {} // Absolutely required!!! }; struct Number : public Value { int data; void write_to(std::ostream & stream) const { stream << ""; } void read_from(std::istream & stream) { stream >> data; // Not the same format as write_to, shame on me } // Implicit destructor is fine }; struct String : public Value { std::string data; void write_to(std::ostream & stream) const { stream << ""; } void read_from(std::istream & stream) { stream >> data; // Not the same format as write_to, shame on me } }; 

    Usando esto, ahora puede, por ejemplo, almacenar Value cuyo tipo real puede dejar que el usuario decida:

     std::vector> values; while (wantsToEnterMoreValues) { std::string choice = ask("What type of value do you want to enter?"); std::unique_ptr value; if (choice == "string") { value = std::make_unique(); } else if (choice == "number") { value = std::make_unique(); } else { // launch apocalypse } value->read_from(std::cin); values.push_back(value); } 

    Esto es fácilmente extensible a más tipos. Tenga en cuenta que para usar la tipificación dinámica incorporada de C ++ debe ir sin semántica de valores, pero en su lugar debe usar completamente la semántica de referencia, ya sea con referencias reales o (en la mayoría de los casos, la propiedad debe transferirse, como en el ejemplo anterior al vector de values ) utilizando punteros.

    El enfoque dynamic_cast funciona de manera muy similar a esto, excepto que está usando información de tipo de tiempo de ejecución de manera más explícita y no necesita una interfaz unificada (pero tiene mucho más trabajo para mantener su código).

  2. Utilice la función de idioma de la union . Esto solo se ha hecho realmente posible con C ++ 11, donde los miembros de la unión pueden ser construibles sin trivialidad:

     enum class Type { Number, String }; struct Value { Type type; union { std::string string; int number; }; Value(std::string const & s) : type(Type::String), string(s) {} Value(int n) : type(Type::Number), number(n) {} Value(Value const & v) : type(v.type) { switch (type) { case Type::Number: number = v.number; break; case Type::String: new (&string) std::string(v.string); break; default: break; // Launch nuclear missiles } } ~Value() { switch (type) { case Type::String: string.~std::string(); break; default: break; } } }; 

    Como puedes ver, esto es bastante trabajo. Con este enfoque, puede utilizar la semántica del valor, pero no puede extender su Value s tan fácilmente para admitir más tipos. Además, debido al uso de una union , vas a desperdiciar algo de memoria.

Conclusión: debe implementar el comportamiento por su cuenta, pero puede hacerlo exactamente de la manera que desee que se comporte. Por ejemplo: También puede implementar operadores de asignación operador operator=(Value const &) que hacen conversiones de tipo implícitas. También puede usar las implementaciones de boost , como boost::any o boost::variant .

Me gustaría hacer referencia a dos respuestas que he escrito en este sitio sobre el mismo tema, quizás también sean útiles para usted:

También algún código C que es relevante, porque trata de resolver el mismo problema: https://stackoverflow.com/a/35443434/1116364

Nota: Todo el código en esta respuesta está escrito de memoria y no se ha probado. Por lo tanto, sólo sirve como demostración de las técnicas básicas.

A diferencia de Python, C ++ es un lenguaje fuertemente tipado. Esto significa que el tipo de cada objeto se conoce en tiempo de comstackción.

Dicho esto, existe un análogo muy, muy vago que puede aplicarse en algunas circunstancias.

Si tiene un puntero a un objeto cuya clase tiene al menos un método virtual, un dynamic_cast lo convertirá en un puntero a la clase solicitada o en un nullptr . Esto solo funcionará cuando el objeto más derivado al que se apunta incluya ambas clases en su jerarquía, sin ambigüedades.