De manière théorique, void
est ce qui est appelé dans d'autres langues unit
ou top
. Son équivalent logique est True. Toute valeur peut légitimement être convertie en void
(chaque type est un sous-type de void
). Pensez-y comme un ensemble "univers"; il n'y a pas d'opérations communes à toutes les valeurs dans le monde, donc il n'y a pas d'opérations valides sur une valeur de type void
. Autrement dit, vous dire que quelque chose appartient à l'ensemble univers ne vous donne aucune information - vous le savez déjà. Donc ce qui suit est correct:
(void)5;
(void)foo(17); // quoi que foo(17) fasse
Mais l'assignation ci-dessous ne l'est pas:
void raise();
void f(int y) {
int x = y!=0 ? 100/y : raise(); // raise() renvoie void, donc quelle devrait être la valeur de x?
cout << x << endl;
}
[[noreturn]]
, d'autre part, est parfois appelé empty
, Nothing
, Bottom
ou Bot
et est l'équivalent logique de False. Il n'a aucune valeur du tout, et une expression de ce type peut être convertie en (c'est-à-dire est un sous-type de) n'importe quel type. C'est l'ensemble vide. Notez que si quelqu'un vous dit "la valeur de l'expression foo() appartient à l'ensemble vide", c'est très informatif - cela vous dit que cette expression ne terminera jamais son exécution normale; elle va avorter, lancer une exception ou se bloquer. C'est exactement l'opposé de void
.
Donc ce qui suit n'a pas de sens (pseudo-C++, puisque noreturn
n'est pas un type à part entière en C++)
void foo();
(noreturn)5; // clairement un mensonge; l'expression 5 "retourne"
(noreturn)foo(); // foo() renvoie void, et donc retourne
Mais l'affectation ci-dessous est parfaitement légitime, puisque throw
est compris par le compilateur comme n'étant pas une fonction de retour:
void f(int y) {
int x = y!=0 ? 100/y : throw exception();
cout << x << endl;
}
Dans un monde parfait, vous pourriez utiliser noreturn
comme valeur de retour pour la fonction raise()
ci-dessus:
noreturn raise() { throw exception(); }
...
int x = y!=0 ? 100/y : raise();
Malheureusement, C++ ne le permet pas, probablement pour des raisons pratiques. Au lieu de cela, il vous donne la possibilité d'utiliser l'attribut [[ noreturn ]]
qui aide à guider les optimisations du compilateur et les avertissements.
2 votes
Qu'est-ce qui est si important à propos de ce genre de fonction (qui se produira très probablement une fois pendant l'exécution d'un programme) qui mérite une telle attention? N'est-ce pas une situation facilement détectable?
3 votes
@MrLister L'OP confond les concepts de "returning" et "return value". Étant donné qu'ils sont presque toujours utilisés ensemble, je pense que la confusion est justifiée.