Dans le projet sur lequel je travaille actuellement, je me retrouve à écrire beaucoup de code qui ressemble à ce qui suit, où get_optional_foo
renvoie un std :: facultatif:
//... auto maybe_foo = get_optional_foo(quux, ...) if (!maybe_foo.has_value()) return {}; auto foo = maybe_foo.value() //... // continue on, doing things with foo...
Je veux renflouer la fonction si j'obtiens une option nulle; sinon, je souhaite attribuer une variable non facultative à la valeur. J'ai commencé à utiliser la convention de nommer l'option avec un maybe_
préfixe mais me demande s'il y a une façon de le faire de telle sorte que je ne ai pas besoin d'utiliser pour l'option temporaire du tout? Cette variable ne sera jamais utilisée que pour vérifier une option nulle et déréférencer s'il y a une valeur.
3 Réponses :
Le plus court auquel je puisse penser:
try { auto &foo = get_optional_foo(quux, ...).value(); auto &bar = get_optional_bar(...).value(); ... } catch (std::bad_optional_access &e) { return {}; }
Si vous avez plusieurs options dans la fonction et qu'il est très peu probable qu'elles soient vides, vous pouvez envelopper le tout avec un try - catch
.
auto maybe_foo = get_optional_foo(quux, ...) if (!maybe_foo) return {}; auto &foo = *maybe_foo; // alternatively, use `*maybe_foo` below
Si vous voulez plus court, vous pouvez écrire return maybe_foo ? *maybe_foo : {}
.
Si nous voulions revenir, nous pourrions simplement utiliser return maybe_foo.value_or({});
bien que.
@ypnos Clang se plaint de ceci: error: initializer list cannot be used on the right hand side of operator ':'
.
@Kostas Cela ferait un appel de constructeur par défaut inutile si la condition est fausse.
@HolyBlackCat Pour value_or({})
? Je suis sûr que tout compilateur décent est heureux d'optimiser cela avec une élision de copie.
Ce que je dis, c'est que si l'option facultative stocke déjà une valeur, {}
construira toujours par défaut un nouvel objet, même si ce n'est pas nécessaire. Si le corps du constructeur par défaut n'est pas visible, le compilateur doit supposer qu'il pourrait avoir des effets secondaires et doit l'appeler.
Vous n'avez pas besoin d'un objet intermédiaire. std::optional
prend en charge une interface de pointeur pour y accéder afin que vous puissiez simplement l'utiliser comme:
//... auto foo = get_optional_foo(quux, ...) if (!foo) return {}; //... foo->some_member; (*foo).some_member;
Légèrement différent de ce que vous demandez, mais considérez:
if (auto foo = get_optional_foo(1)) { // ... return foo->x; } else { return {}; }
Cela place le corps principal de la fonction dans un bloc if()
, qui peut être plus lisible.
Pourquoi ne pas simplement le traiter comme un pointeur?
auto foo = get_optional_foo(quux, ...) if (!foo) return {}; ... foo->some_member;
la syntaxe de la flèche fonctionne avec std :: facultatif?
Oui. Il est fait pour émuler un pointeur sauf aucune allocation dynamique. Vous pouvez également le déréférencer.
Je ne savais pas cela. Écrivez-le comme une réponse et je l'accepterai.
Si vous en avez beaucoup, ajoutez .value () après l'appel et attrapez std :: bad_optional_access