Почему должен void
быть неполным типом?
Есть много причин.
Самое простое это: moo FuncName(...)
все равно должен что-то возвращать. Является ли это нейтральным значением, является ли это «значением не значения», или чем-то еще; он все равно должен сказать return value;
, где value
- это какое-то действительное значение. Надо сказать return moo();
.
Зачем писать функцию, которая технически возвращает что-то, если она на самом деле не возвращает что-то? Компилятор не может оптимизировать возвращаемый результат, потому что он возвращает значение полного типа. Абонент может использовать его.
C ++ не все шаблоны, вы знаете. Компилятор не обязательно обладает знаниями, чтобы выбросить все. Часто приходится выполнять оптимизацию в функции, в которой нет сведений о внешнем использовании этого кода.
void
в данном случае означает «Я ничего не возвращаю». Существует фундаментальная разница между этим и «я возвращаю бессмысленную ценность». Это допустимо:
moo FuncName(...) { return moo(); }
moo x = FuncName(...);
Это в лучшем случае вводит в заблуждение. Беглый просмотр предполагает, что значение возвращается и сохраняется. Идентификатор x
теперь имеет значение и может использоваться для чего-либо.
Тогда как это:
void FuncName(...) {}
void x = FuncName(...);
- ошибка компилятора. Так это:
void FuncName(...) {}
moo x = FuncName(...);
Понятно, что происходит: FuncName
не имеет возвращаемого значения.
Даже если вы разрабатываете C ++ с нуля, без задержек от C, вам все равно понадобится какое-то ключевое слово, чтобы указать разницу между функцией, которая возвращает значение, и функцией, которая не возвращает.
Кроме того, void*
является особенным, потому что void
не является полным типом. Поскольку стандарт требует, чтобы он не был полным типом, концепция void*
может означать «указатель на нетипизированную память». Это специализированная семантика литья. Указатели на типизированную память могут быть неявно приведены к нетипизированной памяти. Указатели на нетипизированную память можно явно привести к типизированному указателю, как это было раньше.
Если вместо этого использовать moo*
, то семантика становится странной. У вас есть указатель на напечатанную память. В настоящее время C ++ определяет приведение между несвязанными типизированными указателями (за исключением определенных особых случаев) как неопределенное поведение. Теперь стандарт должен добавить еще одно исключение для типа moo
. Он должен сказать, что происходит, когда вы делаете это:
moo *m = new moo;
*moo;
С void
это ошибка компилятора. Что это с moo
? Это все еще бесполезно и бессмысленно, но компилятор должен это разрешить.
Если честно, я бы сказал, что лучшим вопросом будет «Почему void
должен быть завершенный тип?»