Теоретично кажучи, voidце те, що називається іншими мовамиunit або top. Його логічний еквівалент - True . Будь-яке значення може бути законно передано void(кожен тип є підтипом void). Подумайте про це як про "Всесвіт"; немає жодних операцій, спільних для всіх значень у світі, тому немає дійсних операцій зі значенням типу void. По-іншому, кажучи вам, що щось належить до набору Всесвіту, ви не має жодної інформації - ви це вже знаєте. Отже, звук наступний:
(void)5;
(void)foo(17); // whatever foo(17) does
Але призначення нижче:
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]]з іншого боку, називається іноді empty , Nothing, Bottomабо Botі є логічним еквівалентом False . Він взагалі не має значень, і вираз цього типу може бути передано (тобто є підтипом) будь-якого типу. Це порожній набір. Зауважте, що якщо хтось скаже вам, що "значення виразу foo () належить порожньому набору", воно є дуже інформативним - воно говорить вам про те, що цей вираз ніколи не завершить його нормальне виконання; вона перерве, кине або повісить. Це якраз навпаки void.
Отже, наступне не має сенсу (псевдо-С ++, оскільки noreturnне є першокласним типом С ++)
void foo();
(noreturn)5; // obviously a lie; the expression 5 does "return"
(noreturn)foo(); // foo() returns void, and therefore returns
Але завдання нижче є цілком законним, оскільки throwкомпілятор розуміє, що він не повертається:
void f(int y) {
int x = y!=0 ? 100/y : throw exception();
cout << x << endl;
}
У ідеальному світі ви можете використати noreturnяк повернене значення для функції, raise()наведеної вище:
noreturn raise() { throw exception(); }
...
int x = y!=0 ? 100/y : raise();
На жаль, C ++ цього не дозволяє, можливо, з практичних причин. Натомість це дає вам можливість використовувати [[ noreturn ]]атрибут, який допомагає керувати оптимізаціями та попередженнями компілятора.