Tipo teóricamente hablando, void
es lo que se llama en otros idiomas unit
o top
. Su equivalente lógico es Verdadero . Cualquier valor se puede emitir legítimamente void
(cada tipo es un subtipo de void
). Piense en ello como un conjunto de "universo"; no hay operaciones en común con todos los valores del mundo, por lo que no hay operaciones válidas para un valor de tipo void
. Dicho de otra manera, diciéndole que algo pertenece al conjunto del universo no le proporciona información alguna, ya lo sabe. Entonces lo siguiente es sólido:
(void)5;
(void)foo(17); // whatever foo(17) does
Pero la tarea a continuación no es:
void raise();
void f(int y) {
int x = y!=0 ? 100/y : raise(); // raise() returns void, so what should x be?
cout << x << endl;
}
[[noreturn]]
Por otra parte, a veces se llama empty
, Nothing
, Bottom
o Bot
y es el equivalente lógico de Falso . No tiene ningún valor en absoluto, y una expresión de este tipo se puede convertir a (es decir, es un subtipo de) cualquier tipo. Este es el conjunto vacío. Tenga en cuenta que si alguien le dice que "el valor de la expresión foo () pertenece al conjunto vacío" es muy informativo: le dice que esta expresión nunca completará su ejecución normal; abortará, arrojará o colgará. Es exactamente lo contrario de void
.
Entonces, lo siguiente no tiene sentido (pseudo-C ++, ya noreturn
que no es un tipo de C ++ de primera clase)
void foo();
(noreturn)5; // obviously a lie; the expression 5 does "return"
(noreturn)foo(); // foo() returns void, and therefore returns
Pero la tarea a continuación es perfectamente legítima, ya que throw
el compilador entiende que no se devuelve:
void f(int y) {
int x = y!=0 ? 100/y : throw exception();
cout << x << endl;
}
En un mundo perfecto, podría usar noreturn
como valor de retorno para la función raise()
anterior:
noreturn raise() { throw exception(); }
...
int x = y!=0 ? 100/y : raise();
Lamentablemente, C ++ no lo permite, probablemente por razones prácticas. En cambio, le brinda la capacidad de utilizar [[ noreturn ]]
atributos que ayudan a guiar las optimizaciones y advertencias del compilador.