C++ estándar:cualquiera Ejemplos

C Estandar Cualquiera Ejemplos



En la programación C++, 'std::any' de la Biblioteca de plantillas estándar (STL) introduce una escritura dinámica para manejar datos heterogéneos. A diferencia de los contenedores tradicionales, “std::any” permite almacenar valores de cualquier tipo dentro de un solo contenedor, mejorando la flexibilidad en escenarios donde los tipos de datos son desconocidos o varían en tiempo de ejecución. Este enfoque independiente del tipo promueve una programación genérica que permite a los desarrolladores crear un código más adaptable y expresivo manteniendo la seguridad del tipo. En esta exploración, profundizaremos en las características de 'std::any', sus patrones de uso y ejemplos prácticos que ilustran su papel en la escritura de un código C++ robusto y flexible.

Ejemplo 1: uso básico de Std::Any

Primero, exploremos un ejemplo sencillo para demostrar el uso fundamental de 'std::any'. Considere un escenario en el que necesita una función para aceptar varios tipos de parámetros:







Aquí está el fragmento de código:



#incluir
#incluir

proceso nuloCualquiera ( constante estándar::cualquiera & valor ) {
    si ( valor.tiene_valor ( ) ) {
std::cout << 'Tipo de valor almacenado: ' << tipo de valor ( ) .nombre ( ) << std::endl;

        si ( tipo de valor ( ) == ID de tipo ( En t ) ) {
std::cout << 'Valor: ' << std::any_cast < En t > ( valor ) << std::endl;
        } demás si ( tipo de valor ( ) == ID de tipo ( doble ) ) {
std::cout << 'Valor: ' << std::any_cast < doble > ( valor ) << std::endl;
        } demás si ( tipo de valor ( ) == ID de tipo ( std::cadena ) ) {
std::cout << 'Valor: ' << std::any_cast < std::cadena > ( valor ) << std::endl;
        } demás {
std::cout << '¡Tipo no admitido!' << std::endl;
        }
    } demás {
std::cout << 'No hay ningún valor almacenado en std::any.' << std::endl;
    }
}

ent principal ( ) {
procesoCualquiera ( 42 ) ;
procesoCualquiera ( 3.14 ) ;
procesoCualquiera ( std::cadena ( 'Hola, std::cualquiera!' ) ) ;
procesoCualquiera ( 4.5f ) ; // No compatible tipo

    devolver 0 ;
}

 
En este ejemplo, definimos la función 'processAny' que toma una referencia 'std::any' como parámetro y examina su contenido. Dentro de la función, primero verificamos si la variable 'std::any' tiene un valor almacenado usando has_value(). Si hay un valor presente, determinamos el tipo del valor almacenado usando type().name() y procedemos a imprimir el valor correspondiente según su tipo. Luego, la función principal demuestra la utilidad de 'processAny' llamándolo con diferentes tipos: un número entero (42), un doble (3.14) y una cadena ('Hello, std::any!'). La función maneja adecuadamente cada tipo e imprime los valores respectivos. Sin embargo, al intentar procesar un número de punto flotante (4.5f), que no es compatible en este ejemplo, el programa maneja elegantemente la situación indicando que el tipo no es compatible.



La salida generada es:






Esto muestra cómo 'std::any' permite el manejo dinámico de varios tipos de datos, convirtiéndolo en una herramienta versátil para la programación genérica en C++.

Ejemplo 2: almacenar los tipos definidos por el usuario

El segundo ejemplo explora cómo este tipo dinámico dentro de la Biblioteca de plantillas estándar (STL) se adapta perfectamente a las estructuras de datos personalizadas. Centrándonos en un tipo definido por el usuario, la estructura de puntos, mostramos cómo “std::any” maneja las instancias de dichas estructuras.



Aquí está el código:

#incluir
#incluir

clase MiClase {
público:
Mi clase ( valor entero ) : datos ( valor ) { }

anular datos de impresión ( ) constante {
std::cout << 'Datos en MiClase: ' << datos << std::endl;
    }

privado:
datos enteros;
} ;

ent principal ( ) {
std::cualquier cualquierObjeto = MiClase ( 42 ) ;

    si ( cualquierObjeto.tiene_valor ( ) ) {
auto & myClassInstance = std::any_cast < Mi clase &> ( cualquier objeto ) ;
miInstanciaDeClase.printData ( ) ;
    } demás {
std::cout << 'No hay ningún valor almacenado en std::any.' << std::endl;
    }

    devolver 0 ;
}

 
En este fragmento de código C++, creamos un ejemplo simple para ilustrar el uso del tipo 'std::any' con una clase definida por el usuario llamada 'MyClass'. Dentro de la clase, hay una variable miembro privada llamada 'datos' y un método público llamado printData() para mostrar el valor de estos datos. Se pasa un valor entero y se asigna al miembro 'datos' en el constructor.

En la función 'principal', creamos una instancia de un objeto de 'MyClass' con un valor inicial de 42 y luego lo almacenamos en la variable 'std::any' llamada 'anyObject'. Esto demuestra la capacidad de 'std::any' para contener instancias de clases definidas por el usuario.

Después de esto, usamos una declaración 'si' para verificar si 'cualquierObjeto' tiene un valor usando el método has_value(). Si hay un valor, recuperamos el objeto almacenado usando 'std::any_cast'. 'std::any_cast' se emplea con el argumento de plantilla 'MyClass&' para convertir el objeto almacenado a una referencia de 'MyClass'. Esta referencia, 'myClassInstance', se utiliza luego para llamar al método printData(), mostrando la capacidad de acceder y operar en el tipo almacenado definido por el usuario dentro de 'std::any'.

Si no se almacena ningún valor en 'std::any', imprimimos un mensaje indicando esto. Esta verificación condicional garantiza que manejamos los escenarios en los que la variable 'std::any' podría estar vacía.

Aquí está el resultado:

Ejemplo 3: Contenedor de tipos mixtos

En programación, un 'contenedor de tipo mixto' se refiere a una estructura de datos que es capaz de contener elementos de tipos de datos diversos y potencialmente no relacionados. Esta flexibilidad es valiosa cuando se trata de escenarios en los que los tipos de datos se desconocen en el momento de la compilación o cambian dinámicamente durante la ejecución del programa. En C++, “std::any” ejemplifica este concepto, permitiendo la creación de un único contenedor para almacenar valores de diferentes tipos.

Exploremos un escenario en el que creamos un contenedor que contiene varios tipos:

#incluir
#incluir
#incluir

ent principal ( ) {

estándar::vector < std::cualquiera > contenedor mixto;

contenedor mixto.push_back ( 42 ) ;                      
contenedor mixto.push_back ( 3.14 ) ;                    
contenedor mixto.push_back ( std::cadena ( 'Hola' ) ) ;  
contenedor mixto.push_back ( verdadero ) ;                    

    para ( constante automática & elemento: contenedor mixto ) {
        si ( tipo de elemento ( ) == ID de tipo ( En t ) ) {
std::cout << 'Entero: ' << std::any_cast < En t > ( elemento ) << std::endl;
        } demás si ( tipo de elemento ( ) == ID de tipo ( doble ) ) {
std::cout << 'Doble: ' << std::any_cast < doble > ( elemento ) << std::endl;
        } demás si ( tipo de elemento ( ) == ID de tipo ( std::cadena ) ) {
std::cout << 'Cadena: ' << std::any_cast < std::cadena > ( elemento ) << std::endl;
        } demás si ( tipo de elemento ( ) == ID de tipo ( booleano ) ) {
std::cout << 'Booleano: ' << std::any_cast < booleano > ( elemento ) << std::endl;
        } demás {
std::cout << 'Tipo desconocido' << std::endl;
        }
    }

    devolver 0 ;
}

 
En esta ilustración, demostramos el concepto de un contenedor de tipo mixto usando C++ y la característica 'std::any'. Creamos el 'std::vector' llamado 'mixedContainer' para que sirva como nuestro contenedor para contener los elementos de diferentes tipos de datos. Usando la función 'push_back', completamos este contenedor con varios elementos, incluido un número entero (42), un doble (3.14), una cadena ('Hola') y un booleano (verdadero).

A medida que iteramos a través del 'contenedor mixto' usando un bucle 'for', empleamos la función type() para identificar dinámicamente el tipo de datos de cada elemento. Utilizando 'std::any_cast', extraemos e imprimimos los valores correspondientes según sus tipos. Por ejemplo, si el elemento es de tipo 'int', lo imprimimos como un número entero. Si es de tipo “doble”, lo imprimimos como doble, y así sucesivamente.

Aquí está el resultado generado:

Ejemplo 4: Manejo de errores con Std::Any

El manejo de errores al usar 'std::any' implica verificar si el tipo es compatible o si se almacena un valor. En este ejemplo, demostramos cómo manejar los tipos no admitidos:

#incluir
#incluir

ent principal ( ) {
std::cualquiera miCualquiera = 42 ;

intentar {
   
valor doble = std::any_cast < doble > ( micualquiera ) ;
std::cout << 'Valor: ' << valor << std::endl;
    } atrapar ( const std::bad_any_cast & Es ) {
       
std::cerr << 'Error: ' << e.qué ( ) << std::endl;
    }

    devolver 0 ;
}

 
Empezamos inicializando la variable “std::any”, “myAny”, con el valor 42 de tipo entero. Dentro del siguiente bloque 'try', hacemos un intento explícito de convertir este valor entero en un 'doble' usando la operación 'std::any_cast'. Sin embargo, dado que el tipo real almacenado en 'myAny' es un número entero, esta operación de conversión no es válida para un 'doble', lo que genera un tipo que no coincide.

Para gestionar este posible error correctamente, implementamos el manejo de excepciones con un bloque 'catch' que está diseñado para detectar el tipo de excepción específico de 'std::bad_any_cast'. En caso de una transmisión fallida, se activa el bloque 'catch' y generamos un mensaje de error usando 'std::cerr' para comunicar la naturaleza del error. Esta estrategia de manejo de errores garantiza que nuestro programa pueda manejar con gracia las situaciones en las que el intento de conversión de tipo choca con el tipo real almacenado en la variable 'std::any'.

Conclusión

En este artículo, exploramos las aplicaciones de 'std::any' en C++, un contenedor de tipos dinámicos que se introduce en C++ para valores de diversos tipos. Demostramos su versatilidad a través de varios ejemplos, mostrando escenarios que van desde el uso básico hasta el manejo de tipos definidos por el usuario y colecciones heterogéneas. Demostramos su aplicación práctica en escenarios donde el tipo de datos no se conoce en el momento de la compilación. Además, exploramos las técnicas de manejo de errores, enfatizando la importancia de administrar con elegancia los tipos no admitidos mediante el manejo de excepciones.