Depuis C++ 17, un type std::optional est offert pour représenter le fait d'avoir peut-être quelque chose. Un optional<T> modélise donc un possible T. Par exemple :
#include <optional>
#include <iostream>
using namespace std;
optional<int> division_entiere(int num, int denom) {
if (denom == 0) return {}; // optional vide
return { num / denom }; // optional non vide
}
int main() {
if (int num, denom; cin >> num >> denom)
if (auto quotient = division_entiere(num, denom); quotient) // si on a un résultat...
cout << quotient.value() << endl; // ... alors on l'affiche
}
Un tel type est utile à plusieurs égards, que ce soit pour signaler l'absence d'un résultat; pour signaler une erreur (sans toutefois en donner la nature) sans avoir recours à une levée d'exception; pour modéliser des paramètres optionnels justement; etc.
Les fonctionnalités cles de ce type sont :
Fonctionnalité | Rôle | Exemple |
---|---|---|
Vider un optional<T> ou créer un optional<T> vide |
Un optional<T> sera vide par défaut, si on lui affecte nullopt ou si on appelle sa méthode reset() |
|
Insérer une valeur |
Il est possible d'insérer une valeur dans un optional<T> :
|
|
Tester pour la présence d'une valeur |
Il est possible de tester un optional<T> pour la présence d'une valeur :
|
|
Obtention de la valeur entreposée |
Il est possible d'extraire le T d'un optional<T> de plusieurs manières :
|
|
Comparaisons |
Un optional<T> est comparable à l'aide des opérateurs relationnels et se comporte comme un T, à ceci près qu'un optional<T> vide est plus petit que tout optional<T> non-vide. Deux optional<T> vide sont égaux au sens de == |
|
C'est un chouette type, qui a un mandat clair et qui l'accomplit bien. Notez qu'à moins que votre biblothèque standard ne fasse des acrobaties suspectes avec certains types T, sizeof(<optional<T>>)>sizeof(T). Notez aussi que copier un optional<T> peut être coûteux si copier T est coûteux.
Quelques liens pour enrichir le propos.