C++ std : tous les exemples

C Std Tous Les Exemples



En programmation C++, « std::any » de la Standard Template Library (STL) introduit un typage dynamique pour gérer des données hétérogènes. Contrairement aux conteneurs traditionnels, « std::any » permet de stocker les valeurs de n'importe quel type dans un seul conteneur, améliorant ainsi la flexibilité dans les scénarios où les types de données sont inconnus ou varient au moment de l'exécution. Cette approche indépendante du type favorise une programmation générique qui permet aux développeurs de créer un code plus adaptable et plus expressif tout en maintenant la sécurité des types. Dans cette exploration, nous approfondirons les fonctionnalités de « std::any », ses modèles d'utilisation et des exemples pratiques qui illustrent son rôle dans l'écriture d'un code C++ robuste et flexible.

Exemple 1 : utilisation de base de Std::Any

Tout d’abord, explorons un exemple simple pour démontrer l’utilisation fondamentale de « std :: any ». Prenons un scénario dans lequel vous avez besoin d'une fonction pour accepter différents types de paramètres :







Voici l'extrait de code :



#include
#inclure

Annuler le processusAucun ( const std :: tout & valeur ) {
si ( valeur.has_value ( ) ) {
std :: cout << 'Type de valeur stockée : ' << type de valeur ( ) .nom ( ) << std::endl;

si ( type de valeur ( ) == identifiant de type ( int ) ) {
std :: cout << 'Valeur: ' << std :: any_cast < int > ( valeur ) << std::endl;
} autre si ( type de valeur ( ) == identifiant de type ( double ) ) {
std :: cout << 'Valeur: ' << std :: any_cast < double > ( valeur ) << std::endl;
} autre si ( type de valeur ( ) == identifiant de type ( std :: chaîne ) ) {
std :: cout << 'Valeur: ' << std :: any_cast < std :: chaîne > ( valeur ) << std::endl;
} autre {
std :: cout << « Type non pris en charge ! » << std::endl;
}
} autre {
std :: cout << 'Aucune valeur stockée dans std :: any.' << std::endl;
}
}

int main ( ) {
processusAucun ( 42 ) ;
processusAucun ( 3.14 ) ;
processusAucun ( std :: chaîne ( 'Bonjour, std::any!' ) ) ;
processusAucun ( 4,5f ) ; // Non pris en charge taper

retour 0 ;
}


Dans cet exemple, nous définissons la fonction « processAny » qui prend une référence « std::any » comme paramètre et examine son contenu. Dans la fonction, nous vérifions d'abord si la variable « std::any » a une valeur stockée en utilisant has_value(). Si une valeur est présente, nous déterminons le type de la valeur stockée à l'aide de type().name() et procédons à l'impression de la valeur correspondante en fonction de son type. La fonction principale démontre ensuite l'utilité de « processAny » en l'appelant avec différents types : un entier (42), un double (3.14) et une chaîne (« Bonjour, std :: any ! »). La fonction gère de manière appropriée chaque type et imprime les valeurs respectives. Cependant, lorsque vous tentez de traiter un nombre à virgule flottante (4.5f), qui n'est pas pris en charge dans cet exemple, le programme gère la situation avec élégance en indiquant que le type n'est pas pris en charge.



La sortie générée est :






Cela montre comment « std::any » permet la gestion dynamique de différents types de données, ce qui en fait un outil polyvalent pour la programmation générique en C++.

Exemple 2 : stockage des types définis par l'utilisateur

Le deuxième exemple explore comment ce type dynamique au sein de la bibliothèque de modèles standard (STL) s'adapte de manière transparente aux structures de données personnalisées. En nous concentrant sur un type défini par l'utilisateur, la structure de points, nous montrons comment « std::any » gère les instances de telles structures.



Voici le code :

#include
#inclure

classe MaClasse {
publique:
Ma classe ( valeur entière ) : données ( valeur ) { }

annuler les données d'impression ( ) const {
std :: cout << 'Données dans MaClasse : ' << données << std::endl;
}

privé:
données entières ;
} ;

int main ( ) {
std :: any anyObject = MaClasse ( 42 ) ;

si ( anyObject.has_value ( ) ) {
auto & maClassInstance = std :: any_cast < Ma classe &> ( n'importe quelObjet ) ;
maClassInstance.printData ( ) ;
} autre {
std :: cout << 'Aucune valeur stockée dans std :: any.' << std::endl;
}

retour 0 ;
}


Dans cet extrait de code C++, nous créons un exemple simple pour illustrer l'utilisation du type « std::any » avec une classe définie par l'utilisateur appelée « MyClass ». Au sein de la classe, il existe une variable membre privée appelée « data » et une méthode publique appelée printData() pour afficher la valeur de ces données. Une valeur entière est transmise et affectée au membre « data » dans le constructeur.

Dans la fonction « main », nous instancions un objet de « MyClass » avec une valeur initiale de 42 puis le stockons dans la variable « std :: any » nommée « anyObject ». Cela démontre la capacité de « std :: any » à contenir les instances de classes définies par l'utilisateur.

Ensuite, nous utilisons une instruction « if » pour vérifier si « anyObject » a une valeur en utilisant la méthode has_value(). S'il y a une valeur, nous récupérons l'objet stocké en utilisant « std::any_cast ». Le « std::any_cast » est utilisé avec l'argument de modèle « MyClass& » pour convertir l'objet stocké en une référence de « MyClass ». Cette référence, « myClassInstance », est ensuite utilisée pour appeler la méthode printData(), montrant la possibilité d'accéder et d'opérer sur le type défini par l'utilisateur stocké dans « std :: any ».

Si aucune valeur n'est stockée dans « std::any », nous imprimons un message le signifiant. Cette vérification conditionnelle garantit que nous gérons les scénarios dans lesquels la variable « std :: any » peut être vide.

Voici le résultat :

Exemple 3 : Conteneur de types mixtes

En programmation, un « conteneur de type mixte » fait référence à une structure de données capable de contenir des éléments de types de données divers et potentiellement sans rapport. Cette flexibilité est précieuse lorsqu'il s'agit de scénarios dans lesquels les types de données sont inconnus au moment de la compilation ou changent dynamiquement pendant l'exécution du programme. En C++, « std::any » illustre ce concept, permettant la création d'un conteneur unique pour stocker les valeurs de différents types.

Explorons un scénario dans lequel nous créons un conteneur contenant différents types :

#include
#inclure
#include

int main ( ) {

std :: vecteur < std :: tout > conteneur mixte ;

MixedContainer.push_back ( 42 ) ;
MixedContainer.push_back ( 3.14 ) ;
MixedContainer.push_back ( std :: chaîne ( 'Bonjour' ) ) ;
MixedContainer.push_back ( vrai ) ;

pour ( constante automatique & élément : mixteContainer ) {
si ( élément.type ( ) == identifiant de type ( int ) ) {
std :: cout << « Entier : » << std :: any_cast < int > ( élément ) << std::endl;
} autre si ( élément.type ( ) == identifiant de type ( double ) ) {
std :: cout << 'Double: ' << std :: any_cast < double > ( élément ) << std::endl;
} autre si ( élément.type ( ) == identifiant de type ( std :: chaîne ) ) {
std :: cout << 'Chaîne: ' << std :: any_cast < std :: chaîne > ( élément ) << std::endl;
} autre si ( élément.type ( ) == identifiant de type ( bouffon ) ) {
std :: cout << 'Booléen : ' << std :: any_cast < bouffon > ( élément ) << std::endl;
} autre {
std :: cout << 'Type inconnu' << std::endl;
}
}

retour 0 ;
}


Dans cette illustration, nous démontrons le concept d'un conteneur de type mixte utilisant C++ et la fonctionnalité « std::any ». Nous créons le « std::vector » nommé « mixedContainer » pour servir de conteneur pour contenir les éléments de différents types de données. À l'aide de la fonction « push_back », nous remplissons ce conteneur avec divers éléments dont un entier (42), un double (3.14), une chaîne (« Bonjour ») et un booléen (vrai).

Lorsque nous parcourons le « MixedContainer » à l’aide d’une boucle « for », nous utilisons la fonction type() pour identifier dynamiquement le type de données de chaque élément. En utilisant « std :: any_cast », nous extrayons et imprimons les valeurs correspondantes en fonction de leurs types. Par exemple, si l’élément est de type « int », nous l’imprimons sous forme d’entier. S’il est de type « double », on l’imprime en double, et ainsi de suite.

Voici le résultat généré :

Exemple 4 : Gestion des erreurs avec Std::Any

La gestion des erreurs lors de l'utilisation de « std :: any » implique de vérifier si le type est pris en charge ou si une valeur est stockée. Dans cet exemple, nous montrons comment gérer les types non pris en charge :

#include
#inclure

int main ( ) {
std :: tout monAny = 42 ;

essayer {

valeur double = std :: any_cast < double > ( monTout ) ;
std :: cout << 'Valeur: ' << valeur << std::endl;
} attraper ( const std :: bad_any_cast & C'est ) {

std :: cerr << 'Erreur: ' << e.quoi ( ) << std::endl;
}

retour 0 ;
}


On commence par initialiser la variable « std::any », « myAny », avec la valeur 42 de type entier. Dans le bloc « try » suivant, nous tentons explicitement de convertir cette valeur entière en un « double » en utilisant l'opération « std::any_cast ». Cependant, étant donné que le type réel stocké dans « myAny » est un entier, cette opération de conversion n'est pas valide pour un « double », ce qui conduit à une incompatibilité de type.

Pour gérer cette erreur potentielle avec élégance, nous implémentons la gestion des exceptions avec un bloc « catch » conçu pour intercepter le type d'exception spécifique de « std::bad_any_cast ». En cas d'échec du cast, le bloc « catch » est activé et nous générons un message d'erreur en utilisant « std::cerr » pour communiquer la nature de l'erreur. Cette stratégie de gestion des erreurs garantit que notre programme peut gérer avec élégance les situations dans lesquelles la conversion de type tentée entre en conflit avec le type réel stocké dans la variable « std :: any ».

Conclusion

Dans cet article, nous avons exploré les applications de « std::any » en C++, un conteneur de types dynamiques introduit en C++ pour des valeurs de divers types. Nous avons démontré sa polyvalence à travers divers exemples, présentant des scénarios allant de l'utilisation de base à la gestion des types définis par l'utilisateur et des collections hétérogènes. Nous avons démontré son application pratique dans des scénarios où le type de données n'est pas connu au moment de la compilation. De plus, nous avons exploré les techniques de gestion des erreurs, en soulignant l'importance de gérer gracieusement les types non pris en charge grâce à la gestion des exceptions.