Построение типа пустоты?
Мне был предоставлен фрагмент кода, который использует void()
в качестве аргумента. Код не компилируется... очевидно?
Можно ли создать экземпляр типа void
? Я полагал, что ответа нет, за исключением void*
. Например:
- Написание ошибок функции
void askVoid(void param) {}
:
Параметр может не иметь тип void
- Написание функции
void askNaught() {}
и вызов ее с помощью askNaught (void()) `errors:
ошибка C2660: takeNaught
: функция не принимает 1 аргумент
- Написание темплатной функции
template <typename T> void takeGeneric(T param) {}
и вызов ее с ошибками takeGeneric(void())
:
ошибка C2893: не удалось специализировать шаблон функции void takeGeneric(T)
- Объявление
void voidType
ошибок:
Неполный тип недопустим
- Объявление
auto autoVoid = void()
ошибок:
Невозможно вывести тип auto
- Объявление
void* voidPtr
работает нормально, но remove_pointer_t<decltype(voidPtr)> decltypeVoid
ошибки:
ошибка C2182: decltypeVoid
: незаконное использование типа void
Что, верно? В С++ нет места для void()
? Это просто плохой код, который мне дал, не так ли?
Ответы
Ответ 1
Выражение void()
является prvalue типа void
и может использоваться везде, где может использоваться такое выражение, которое [basic.fundamental]/9 содержит список:
- Как выражение-выражение:
void();
- В качестве второго или третьего операнда условного оператора:
true ? throw 1 : void()
- В качестве операнда оператора запятой:
++it1, void(), ++it2
- В качестве операнда
decltype
или noexcept
: using my_void = decltype(void()); static_assert(noexcept(void()), "WAT");
- В выражении
return
возвращаемой функции (возможно, cv-qualified) void
: const void f() { return void(); }
- В качестве операнда явного преобразования в (возможно, с квалификацией)
void
: static_cast<const void>(void())
Выражение типа void
также может использоваться как операнд typeid
, но void()
в частности будет анализироваться как тип, а не выражение в этом контексте.
Ответ 2
Вы можете принять параметр функции void()
как:
void test(void()) { ... }
Расширяется до:
void test(void (*)())
Это указатель на метод, который возвращает void и не принимает никаких аргументов.
Полный пример:
void abc() {}
void test(void()) { }
int main() {
test(abc);
}
Ответ 3
С++ (и я говорю, что С++, а не C) позволяет (§6.6.3 запятая 2) с возвратным типом void
для возврата a void
, то есть:
void foo() { return void(); }
Но заметьте, что он не создает временную void
!
Ответ 4
Вы можете использовать void()
как вызываемый тип, так как пример std::function<void()> f;
является допустимым оператором.
Кроме того, как из 8.3.5/4:
Список параметров, состоящий из одного неназванного параметра не зависящего от типа типа void, эквивалентен списку пустых параметров.
Это означает, что это действительно:
template<typename T>
struct F;
template<typename R, typename... A>
struct F<R(A...)> { };
int main () {
F<void(void)> s;
}
Здесь вы не создаете экземпляр типа void
, но используете его (скажем) как список параметров вызываемого типа.
Не уверен, что это ответ на ваш вопрос, я не понимаю, на самом деле вопрос.
Ответ 5
В С++ нет места для void()?
В качестве выражения в С++ допустимо void()
.
Из стандарта $5.2.3/2 Explicit type conversion (functional notation) [expr.type.conv]
:
Выражение T()
, где T
- спецификатор простого типа или typename-specifier для типа объекта без массива или (возможно, с квалификацией cv) void
, создает значение заданного значения тип, значение которого выражается посредством инициализации значения (8.5) и объект типа T
; не выполняется инициализация для случая void()
.
Из cppreference.com:
new_type()
Если new_type
- тип объекта, объект инициализируется значением; в противном случае инициализация не выполняется. Если new_type
(возможно cv-qualified) void
, выражение является void
prvalue.