Il y a quelques mois je me réjouissais de la validation du standard C++11. Je regrette toujours que les sockets réseau n’aient pas été implémenté.
Après plusieurs lectures sur le sujet, je recherche l’adoption totale de la nouvelle syntaxe de C++11. Tentons de dompter les nouveautés. Les exemples sont testés avec GCC version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3), le code source est disponible sur GitHub.
Nous allons commencer à travailler sur les types automatiques avec le mot clé auto et l’opérateur decltype.
#include<iostream>
#include<vector>
#include<string>
#include<algorithm>//for_each
#include<typeinfo>//typeid
int main() {
std::vector<std::string> data{"first", "second", "third"};//uniform brace notation
for (const auto item : data) {//Range based for loop
std::cout << "Iterate =>" << std::endl;
std::cout << " Automatic item type: " << typeid(item).name() << " - Item value: " << item << std::endl;
decltype(item) dynamic_value = item;
std::cout << " Dynamic type: " << typeid(dynamic_value).name() << " - Dynamic value: " << dynamic_value << std::endl;
std::cout << std::endl;
}
return 0;
}
Dans cet exemple nous initialisons un vecteur de chaîne de caractères puis bouclons sur chaque item ; le type de chaque item est récupéré automatiquement et nous créons dynamiquement une variable du même type que l’item. Pour le moment ne tenez pas compte de la syntaxe particulière de la boucle for.
Simplification de l’itération simple d’un conteneur avec la structure de contrôle for.
#include<iostream>
#include<vector>
#include<string>
int main() {
std::vector<std::string> data{"first", "second", "third"};
for(const auto item : data) {
std::cout << "Item value: " << item << std::endl;
}
return 0;
}
Une simple boucle for tel que le propose déjà des langages tel que Java ou C#. Un vrai bonheur pour notre langage. Notons que pour un parcours spécifique ou plus complexe, il est plus puissant d’utiliser for_each ; par exemple commencer l’itération à partir du 3ème élément.
Avant C++11, la macro NULL équivalente à 0, est parfois considéré comme très particulière par les développeurs et porte à confusion. C++11 propose une expression nullptr, plus d’excuses et arrêtons d’utiliser 0 ou NULL pour initialiser un pointeur.
#include<iostream>
#include<vector>
int main() {
const int* p = nullptr;
std::vector<int> data{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for (const auto item : data) {
p = &item;
std::cout << "Item pointer: " << *p << std::endl;
}
return 0;
}
On initialise un pointeur avec nullptr et non 0, puis on boucle sur les données en assignant l’adresse de chaque item au pointeur p.
Uniformisation de l’initialisation avec les accolades {}. Avant C++11, selon qu’on veut initialiser un tableau, les membres d’une structures… avec des zéros ou avec des valeurs différentes de zéro, il fallait passer par des syntaxes différentes. Avec C++11 on arrête avec toutes ces possibilités, on uni formalise comme le montre le code source suivant :
#include<string>
#include<sstream>
#include<vector>
struct Version {
uint32_t major;
uint32_t minor;
uint32_t revision;
std::string toString() const {
std::ostringstream oss;
oss << major << "." << minor << "." << revision;
return oss.str();
}
};
int main() {
Version v{0, 1, 0};//Constructor initialization
std::cout << "Version v{0, 1, 0}: " << std::endl;
std::cout << " " << v.toString() << std::endl;
std::vector<Version> vArray{{0, 1, 0}, {0, 1, 1}, {0, 1, 2}};//Array initialization
std::cout << "std::vector<Version> vArray{{0, 1, 0}, {0, 1, 1}, {0, 1, 2}}: " << std::endl;
for (const auto v : vArray) {
std::cout << " " << v.toString() << std::endl;
}
return 0;
}
On crée une instance de Version en initialisant major, minor et revision. On crée ensuite un vecteur de Version en initialisant les 3 premiers éléments.
Les nombres aléatoires, peuvent être générés selon un nouveau modèle qui se compose de deux éléments, un moteur de génération de nombre (il y en a plusieurs au choix) et une distribution soit une plage de nombre pouvant être généré, là encore on a le choix de la distribution ; voir un aperçu via ce lien.
#include<iostream>
#include<random>//std::mt19937, std::uniform_int_distribution
#include<functional>//std::bind
#include<ctime>
std::mt19937 engine;
std::uniform_int_distribution<uint32_t> distribution{1, 10};
int main() {
engine.seed(static_cast<uint32_t>(std::time(nullptr)));
auto generator = std::bind(distribution, engine);
uint32_t random = generator();
std::cout << "1st random: " << random << std::endl;
random = generator();
std::cout << "2nd random: " << random << std::endl;
return 0;
}
Dans cet exemple on instancie le moteur de génération de type Mersenne Twister avec une distribution uniforme d’entier. On initialise dans la méthode main, le moteur avec un nombre entier récupérer de l’horloge de la machine. On se fabrique une fonction generator qui permet d’appeler notre générateur avec un nom plus intuitif.
Voilà c’est une première mise en jambe avec C++11 histoire de s’échauffer. Je reste persuadé du potentiel de ce langage et de son avenir glorieux. C++11 est le langage le plus concis et rapide de la planète.