void
— странная бородавка в системе типов C++. Это незавершенный тип, который не может быть завершен, и у него есть все виды магических правил, ограничивающих способы его использования:
Тип cv
void
— это неполный тип, который не может быть завершен; такой тип имеет пустой набор значений. Он используется в качестве возвращаемого типа для функций, которые не возвращают значение. Любое выражение можно явно преобразовать в тип cvvoid
([expr.cast]). Выражение типа cvvoid
должно использоваться только как оператор выражения, как операнд выражения с запятой, как второй или третий операнд?:
([expr.cond]), как операнд выраженияtypeid
,noexcept
илиdecltype
, как выражение в оператореreturn
для функции с типом возвращаемого значения cvvoid
, или как операнд явного преобразования в тип cvvoid
.
(N4778, [basic.fundamental] ¶9)
Помимо зудящего чувства ко всем этим странным правилам, из-за ограниченных способов их использования это часто становится болезненным частным случаем при написании шаблонов; чаще всего кажется, что мы хотели бы, чтобы он вел себя как std::monostate
.
Давайте представим на мгновение, что вместо приведенной выше цитаты стандарт говорит о void
что-то вроде
Это тип с определением, эквивалентным:
struct void { void()=default; template<typename T> explicit void(T &&) {}; // to allow cast to void };
сохраняя при этом магию void *
- можно использовать псевдоним для любого объекта, указатели данных должны пережить обратный путь через void *
.
Этот:
- должны охватывать существующие варианты использования
void
типа "правильный"; - вероятно, может позволить удалить приличное количество мусора, распространяемого по стандарту - например. [expr.cond] ¶2, вероятно, не понадобится, а [stmt.return] будет значительно упрощен (при сохранении "исключения", которое
return
без выражение разрешено дляvoid
и что "вытекание" функцииvoid
эквивалентноreturn;
); - все еще должен быть таким же эффективным - оптимизация пустого класса в настоящее время поддерживается везде;
- быть внутренне совместимыми с современными ABI, и компилятор может по-прежнему использовать специальный регистр для более старых.
Помимо совместимости, это обеспечит:
- создание, копирование и перемещение этих пустых объектов, исключая особые случаи, обычно необходимые в шаблонах;
- бонусная арифметика указателя на
void *
, работающая как дляchar *
, которая является распространенным расширением, весьма полезным при работе с бинарными буферами.
Теперь, кроме возможных измененных возвращаемых значений <type_traits>
, что это может сломать в коде, правильно построенном в соответствии с текущими (C++17) правилами?
void
выглядят как убийственная функция. - person user7860670   schedule 07.11.2018sizeof(void*) == sizeof(char*)
. Тот факт, что указатели на неполные типы существуют, означает, что все указатели структур пахнут одинаково. Поскольку вы предлагаете, чтобыvoid
была структурой, это означает, чтоsizeof(void*) == sizeof(struct Foo*)
означает, чтоsizeof(char*) == sizeof(struct Foo*)
, что усложняет жизнь системам без байтовой адресации, таким как TOPS-20. - person Raymond Chen   schedule 10.11.2018sizeof(void *) >= sizeof(any other data object)
, это сделало быstruct
указатели слишком большими без уважительной причины? - person Matteo Italia   schedule 10.11.2018sizeof(struct Foo*)
иметь тот же размер, что иsizeof(void*)
, и потребует реализации для поддержки структур с выравниванием по байтам (посколькуvoid
теперь будет структурой с выравниванием по байтам). Для систем без байтовой адресации это увеличивает использование памяти (указатели структур становятся больше) и размер кода (разыменование указателей теперь намного сложнее). - person Raymond Chen   schedule 10.11.2018sizeof(struct Foo*) == sizeof(void *)
. Тот факт, чтоsizeof(struct Foo*) == sizeof(struct Bar*)
, хотя это и не указано явно, AFAIK, исходит из того факта, что любой указатель наstruct
должен быть полным типом, даже еслиFoo
иBar
являются неполными типами (IOW, он не должен зависеть от фактического определенияFoo
иBar
); это не будет применяться кvoid
, так как это будет встроенный тип, то есть всегда уже объявленный, как сейчас. - person Matteo Italia   schedule 10.11.2018