Le mot-clé
auto est un mot-clé utilisable en C++0x qui est différent du mot-clé
auto qui était utilisé avant. Il est possible de le mettre à la place du type de telle sorte que ce type est automagiquement déterminé à la compilation en fonction du type retourné par l’objet utilisé pour l’initialisation.
On parle ici d’
inférence de types.
Donc, il est possible d’écrire le code suivant :
Code : C++
La variable nombre sera de type entier (
int).
Mais, je vous interdis de faire cela !
Si vous initialisez toutes vos variables avec le mot-clé
auto, votre code va vite devenir illisible.
Vous devez utiliser ce mot-clé le moins possible.
As-tu des exemples d’utilisation ?
Oui, en voilà un :
Code : C++ | for(auto i(nombres.begin()) ; i != nombres.end() ; ++i) {
std::cout << *i << std::endl;
}
|
Au lieu de cela :
Code : C++ | for(std::vector<int>::iterator i(nombres.begin()) ; i != nombres.end() ; ++i) {
std::cout << *i << std::endl;
}
|
Mais, encore là, c’est limite.
Si vous utilisez beaucoup de fois un même itérateur, le mieux est de créer un
typedef :
Code : C++ | typedef std::vector<int>::iterator iter_entier;
for(iter_entier i(nombres.begin()) ; i != nombres.end() ; ++i) {
std::cout << *i << std::endl;
}
|
Vous pouvez également utiliser ce mot-clé lorsqu’une même fonction peut retourner différents types de données.
Vous devez faire attention à deux points en particulier :
- Le mot-clé auto n’est pas comme un type qui change au cours de l’exécution du programme. Si j’assigne un entier à une variable dont le mot-clé auto est utilisé à l’initialisation, cette variable sera et restera un entier.
- Vous devez obligatoirement initialiser une variable déclarée avec le mot-clé auto à la déclaration. Autrement dit, il est impossible de faire :
Code : C++
Si je déclare une variable avec le mot-clé auto, puis-je donner le même type à une autre variable ?
Oui, avec le mot-clé
decltype :
Ce mot-clé détermine le type d’une expression.
Code : C++ | auto variable = 5;
decltype(variable) autreVariable;
|
Ainsi, nous sommes sûr que
autreVariable aura le même type (
int) que
variable.
L’inférence de type est très utile lorsque nous utilisons la programmation générique.
Considérez ce programme :
Code : C++ 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 | #include <iostream>
template <typename T>
T maximum(const T& a, const T& b) {
if(a > b) {
return a;
}
else {
return b;
}
}
template <typename T>
T minimum(const T& a, const T& b) {
if(a < b) {
return a;
}
else {
return b;
}
}
int main() {
int a(10), b(20);
auto plusGrand = maximum(a, b);
decltype(plusGrand) plusPetit = minimum(a, b);
std::cout << "Le plus grand est : " << plusGrand << std::endl;
std::cout << "Le plus petit est : " << plusPetit << std::endl;
return 0;
}
|
Ce code détermine, grâce à des fonctions génériques, le plus grand et le plus petit nombres.
Ce qui est intéressant, c’est que nous n’avons besoin que de modifier la première ligne de la fonction
main() si nous voulons essayer ce code avec un autre type.
Remplacez-la par celle-ci et tout fonctionne :
Code : C++
De plus, les mots-clés
auto et
decltype sont obligatoires dans certains cas utilisant la programmation générique.
Considérons l’exemple suivant (assez tordu, je dois l’admettre

) :
Vous avez un programme de gestion des notes obtenues à l’école.
Les examens comportent dix questions (chacune vaut 10 points).
Votre programme stocke les notes de deux manières :
- Un nombre entier sur 100 (le pourcentage) ;
- Un nombre réel sur 1 (le pourcentage divisé par 100).
Vous avez créé une fonction
ajouterDixPourcents() surchargée pour les entiers et les réels :
Code : C++ 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | int ajouterDixPourcents(int nombre) {
if(nombre + 10 <= 100) {
return nombre + 10;
}
else {
return 100;
}
}
float ajouterDixPourcents(float nombre) {
if(nombre + 0.1 <= 1) {
return nombre + 0.1;
}
else {
return 1;
}
}
|
Pour une raison inconnue

, vous créez également une fonction générique
ajouter() qui appellera la fonction
ajouterDixPourcents().
Cette fonction doit retourner le même type que celui retourné par cette dernière.
Mais, comment faire pour déterminer ce type ?
Nous pourrions utiliser le mot-clé auto, non ?
Impossible, car il se base sur le type de l’objet qu’on lui affecte. Le compilateur ne saura pas sur quel objet se baser.
Avec decltype(), alors ?
Encore une fois, c’est impossible.
En effet, quelle expression lui passerions-nous pour déterminer le type de retour de la fonction
ajouter() ?
La solution est d’utiliser les deux mots-clés en utilisant une syntaxe alternative pour le prototype de la fonction ! (Vous ne pouviez pas vraiment le deviner.

)
Voilà enfin la fonction
ajouter() :
Code : C++ | template <typename T> auto ajouter(T nombre) -> decltype(ajouterDixPourcents(nombre)) {
return ajouterDixPourcents(nombre);
}
|
Il est impossible d’utiliser decltype(ajouterDixPourcents(nombre)) à la place du type de retour, car nombre n’a pas encore été parsé par le compilateur.
Vous pouvez maintenant utiliser votre fonction générique
ajouter() dans votre code :
Code : C++ | int main() {
int pourcentageEntier(42);
float pourcentageFlottant = pourcentageEntier / 100.f;
std::cout << pourcentageFlottant << " = " << pourcentageEntier << "%" << std::endl;
pourcentageEntier = ajouter(pourcentageEntier);
pourcentageFlottant = ajouter(pourcentageFlottant);
std::cout << pourcentageFlottant << " = " << pourcentageEntier << "%" << std::endl;
}
|
Étant donnée que nous utilisons
auto et
decltype dans une fonction dont le prototype est plutôt long, je vous donne un exemple plus simple pour comprendre :
Code : C++ | auto cinq() -> int {
return 5;
}
|
Nous utilisons le mot-clé
auto à la place d’indiquer un type de retour.
Il faut donc préciser le type de retour après la parenthèse fermante sous la forme suivante :
Code : C++
type peut être un type prédéfini comme
int, mais la plupart du temps, nous utiliserons
decltype(expression).