23

I was given a piece of code that uses void() as an argument. The code doesn't compile... obviously?

Can we instantiate anything of type void? I believed the answer was no, with the exception of a void*. For example:

  1. Writing the function void askVoid(void param) {} errors:

A parameter may not have void type

  1. Writing the function void askNaught() {} and calling it with askNaught(void())` errors:

error C2660: takeNaught: function does not take 1 arguments

  1. Writing the templatized function template <typename T> void takeGeneric(T param) {} and calling it with takeGeneric(void()) errors:

error C2893: Failed to specialize function template void takeGeneric(T)

  1. Declaring void voidType errors:

Incomplete type is not allowed

  1. Declaring auto autoVoid = void() errors:

Cannot deduce auto type

  1. Declaring void* voidPtr works fine, but remove_pointer_t<decltype(voidPtr)> decltypeVoid errors:

error C2182: decltypeVoid: illegal use of type void

That's it, right? There is no place for void() in C++ is there? This is just bad code I've been given, right?

edmz
  • 8,220
  • 2
  • 26
  • 45
Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • 2
    You can return a `void` function call in a function that returns `void`: `void a() {}; void b() { return a(); }`. That's kind of an expression of type void. – rodrigo Jun 08 '16 at 11:56
  • @rodrigo In this case `a()` would be executed? That's very odd, but my compiler doesn't complain. Similar to just calling `a()` as the last line of `b()` I guess. – Jonathan Mee Jun 08 '16 at 13:18
  • 3
    Yes, it is the same as just calling the function and then returning. It is a special rule in the C++ type system to ease the writing of templates: `template T foo() { return bar(); }`. Or else you would need a template specialization just to remove the spurious `return`s when `T=void`. – rodrigo Jun 08 '16 at 14:52
  • @rodrigo Amazing, I see the importance of being able to call `return` with a `void` when you put it in that context. I'd suggest you put it into an answer, but it looks like [Black got there first](http://stackoverflow.com/a/37701815/2642059), although that does not use the type it does in effect what I was asking about. – Jonathan Mee Jun 08 '16 at 15:02
  • Actually, writing @Black 's answer just covers the original question, IMO. I invite him to copy the template stuff from my comment if he wishes. – rodrigo Jun 08 '16 at 15:48

5 Answers5

12

C++ (and I say C++, not C) allows (§6.6.3 comma 2) functions with void return type to return a void expression, that is:

void foo() { return void(); }

But notice it is not constructing a temporary void!

edmz
  • 8,220
  • 2
  • 26
  • 45
  • 2
    Fascinating. So this is just equivalent to `return` right? – Jonathan Mee Jun 08 '16 at 12:58
  • @JonathanMee Yes, it's right. @rodrigo gave an immediate consequence of this usage i.e. when you call a function returning `void`. – edmz Jun 08 '16 at 14:05
  • Yeah I get the impression that that's actual the functional use of this to compress a closing function call (@rodrigo's `a()`) and an early return from a function returning `void` into one compound statement. – Jonathan Mee Jun 08 '16 at 14:11
  • 9
    This is used heavily in generic code to avoid having to special case `void` returning functions whose result you are "passing through". – Yakk - Adam Nevraumont Jun 08 '16 at 15:30
12

The expression void() is a prvalue of type void and can be used anywhere such an expression may be used, which [basic.fundamental]/9 helpfully provides a list:

  • As an expression-statement: void();
  • As the second or third operand of a conditional operator: true ? throw 1 : void()
  • As an operand of the comma operator: ++it1, void(), ++it2
  • As the operand of decltype or noexcept: using my_void = decltype(void()); static_assert(noexcept(void()), "WAT");
  • In a return statement of a function returning (possibly cv-qualified) void: const void f() { return void(); }
  • As an operand of an explicit conversion to (possibly cv-qualified) void: static_cast<const void>(void())

An expression of type void can also be used as the operand of typeid, but void() in particular would be parsed as a type, not an expression, in this context.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • Does the standard mention anywhere that `void()` is non-throwing? Or, put differently, how are we expected to know what `noexcept(void())` returns? – 303 Nov 19 '22 at 18:08
10

You can take a void() as function parameter:

void test(void()) { ... }

Which expands to:

void test(void (*)())

Which is a function pointer to a method which returns void and takes no arguments.

Full example:

void abc() {}
void test(void()) { }

int main() {
    test(abc);
}
tobspr
  • 8,200
  • 5
  • 33
  • 46
  • 1
    No, if you use `test(void)` you are indicating a method which takes no arguments (which was required in C) - or am I wrong? – tobspr Jun 08 '16 at 11:38
  • you're right, I realized my comment was off-topic and deleted it, feel free to delete both of our comments as the matter is resolved – sokkyoku Jun 08 '16 at 11:39
  • @sokkyoku I think it wasn't necessary to delete it, it could have helped others too to clarify why the braces matter :) – tobspr Jun 08 '16 at 11:40
  • Fair enough, it has no impact in C++ though, you can still specify a lone `void` keyword for parameters in the prototype but it no longer has an effect I believe. – sokkyoku Jun 08 '16 at 11:42
  • Snap! That is cray cray. That's [`function`](http://en.cppreference.com/w/cpp/utility/functional/function) syntax for a function type. Are you saying that we can abandon the C-style function pointer all together now? Did that change sometime? I thought that was illegal? – Jonathan Mee Jun 08 '16 at 11:49
  • @JonathanMee: That comment makes little sense to me. You link to `std::function`, which is a C++ library type. This example is valid since ANSI C'89. Did you perhaps intend to comment on skypjack's answer? – MSalters Jun 08 '16 at 12:23
  • @MSalters This is just my ignorance, I thought that we always had to have the `void(*)()` syntax. I'd never seen the `void()` syntax outside a `function` type anyway. I guess it's been valid about as long as I've been alive. – Jonathan Mee Jun 08 '16 at 12:32
  • @JonathanMee the syntax exists for way longer than `std::function`, you can write `int (double, short)` to denote a function which returns an integer and takes a double and a short for example. `std::function` just provides a nicer interface – tobspr Jun 08 '16 at 12:39
  • 3
    @JonathanMee: `void(*)()` is a _function **pointer** type_. `void()` is a _function type_. The two are related, but [not the same](http://ideone.com/Od7kvo). – MSalters Jun 08 '16 at 12:42
  • The question was about the type `void` and the expression `void()`. This answer is about the type `void()`, which is something completely different. – interjay Jun 08 '16 at 15:55
  • 1
    @interjay the question starts with "I was given a piece of code that uses void() as an argument" so I think this is still related – tobspr Jun 08 '16 at 15:57
  • Also, what `void()` does in that context is _decaying_, not expanding (it's not a macro). – edmz Jun 09 '16 at 09:09
4

You can use void() as a callable type, as an example std::function<void()> f; is a valid statement.

Moreover, as from 8.3.5/4:

A parameter list consisting of a single unnamed parameter of non-dependent type void is equivalent to an empty parameter list.

That means that this is valid:

template<typename T>
struct F;

template<typename R, typename... A>
struct F<R(A...)> { };

int main () {
   F<void(void)> s;
}

Here you are not instantiating anything of type void, but you are using it (let me say) as a parameter list of a callable type.

Not sure if this replies to your question, I've not clear what the question actually is.

skypjack
  • 49,335
  • 19
  • 95
  • 187
1

There is no place for void() in C++ is there?

As an expression, void() is valid in C++.

From the standard, $5.2.3/2 Explicit type conversion (functional notation) [expr.type.conv]:

The expression T(), where T is a simple-type-specifier or typename-specifier for a non-array complete object type or the (possibly cv-qualified) void type, creates a prvalue of the specified type, whose value is that produced by value-initializing (8.5) an object of type T; no initialization is done for the void() case.

From cppreference.com:

new_type ( )

If new_type is an object type, the object is value-initialized; otherwise, no initialization is done. If new_type is (possibly cv-qualified) void, the expression is a void prvalue.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • I'm reading from here: http://en.cppreference.com/w/cpp/language/explicit_cast and I see what you're talking about, but I don't see where that works. I mean I tried `void()` in all the contexts I could think of. – Jonathan Mee Jun 08 '16 at 16:39
  • @JonathanMee What context did you try? BTW: T.C. 's answer provids a list for it. – songyuanyao Jun 08 '16 at 16:41