Digite teoricamente falando, void
é o que é chamado em outros idiomas unit
ou top
. Seu equivalente lógico é True . Qualquer valor pode ser legitimamente convertido para void
(todo tipo é um subtipo de void
). Pense nisso como um conjunto de "universo"; não há operações em comum a todos os valores no mundo, para que não haja operações válidas em um valor do tipo void
. Dito de outra maneira, dizer que algo pertence ao conjunto do universo não fornece nenhuma informação - você já sabe disso. Portanto, o seguinte é válido:
(void)5;
(void)foo(17); // whatever foo(17) does
Mas a tarefa abaixo não é:
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 outro lado, é chamado às vezes empty
, Nothing
, Bottom
ou Bot
e é o equivalente lógico de Falso . Ele não possui valores, e uma expressão desse tipo pode ser convertida para (ou seja, é subtipo de) qualquer tipo. Este é o conjunto vazio. Observe que se alguém lhe disser "o valor da expressão foo () pertence ao conjunto vazio" é altamente informativo - informa que essa expressão nunca concluirá sua execução normal; irá abortar, jogar ou travar. É exatamente o oposto de void
.
Portanto, o seguinte não faz sentido (pseudo-C ++, pois noreturn
não é do tipo C ++ de primeira classe)
void foo();
(noreturn)5; // obviously a lie; the expression 5 does "return"
(noreturn)foo(); // foo() returns void, and therefore returns
Mas a atribuição abaixo é perfeitamente legítima, pois throw
é entendida pelo compilador como não retornando:
void f(int y) {
int x = y!=0 ? 100/y : throw exception();
cout << x << endl;
}
Em um mundo perfeito, você pode usar noreturn
como valor de retorno para a função raise()
acima:
noreturn raise() { throw exception(); }
...
int x = y!=0 ? 100/y : raise();
Infelizmente, o C ++ não permite isso, provavelmente por razões práticas. Em vez disso, oferece a capacidade de usar [[ noreturn ]]
atributos que ajudam a orientar otimizações e avisos do compilador.