17

Apparently, this ternary expression with void() as one argument compiles:

void foo() {}

//...
a == b ? foo() : void();

Is void() a valid expression by the standard, or is it just a compiler thing? If it's valid, then what kind of expression is it?

petiaccja
  • 171
  • 6
  • 9
    This is just someone trying to be smart. `if(a==b){ foo(); }` is clearer and has the same effect. – Not a real meerkat Jan 28 '20 at 20:38
  • 1
    @CássioRenan your version can't be used in an expression though . – M.M Jan 28 '20 at 20:40
  • @M.M yes, but I really can't think of any useful way this could be used on an expression either, seeing that you cannot create objects of type `void`. (Although I will be the first to say that me not being able to think of one doesn't mean it can't exist) – Not a real meerkat Jan 28 '20 at 20:46
  • Maybe it could occur in a parameter pack expansion, or some template metaprogramming where `void` came from a template type and this expression is argument to another function call – M.M Jan 28 '20 at 20:52
  • @M.M you can't pass `void()` as an argument. – Not a real meerkat Jan 28 '20 at 21:00
  • @CássioRenan: Possible usage of `void()`: with SFINAE: `template auto bar(T t) -> decltype(func(t), void())` (return type is `void`) Or to handle evil overload of comma operator: `(f1(t), void(), f2(t))`. – Jarod42 Jan 28 '20 at 22:05
  • @Jarod42 I never argued that `void()` is not useful. I know it is very useful in metaprogramming (that's why `std::void_t` is a thing). I'm arguing specifically about `a==b?foo():void()`. If you were to put this expression in `decltype`, for instance, then you don't really need the ternary operator, since neither the boolean expression will be checked, nor `foo()` actually be called. Same for handling of comma operator. – Not a real meerkat Jan 28 '20 at 23:21
  • @CássioRenan: It would be `decltype(a == b ? foo() : void())` versus `decltype(a==b, void(), foo(), void())` (former is shorter even if I prefer the later). – Jarod42 Jan 29 '20 at 08:46
  • What's the point of answering the same question so many times when we have duplicate system? – xinaiz Jan 29 '20 at 09:43

2 Answers2

21

void() is a valid expression and yields a prvalue of type void. In C++ 20 this will be expanded to also include void{}. The relevant section for this is [expr.type.conv]/2

If the initializer is a parenthesized single expression, the type conversion expression is equivalent to the corresponding cast expression. Otherwise, if the type is cv void and the initializer is () or {} (after pack expansion, if any), the expression is a prvalue of the specified type that performs no initialization. Otherwise, the expression is a prvalue of the specified type whose result object is direct-initialized with the initializer. If the initializer is a parenthesized optional expression-list, the specified type shall not be an array type.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • So, `void{}` should compile but it doesn't. According to [this](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1114r0.html#2351) it should. But why it doesn't? – NutCracker Jan 28 '20 at 20:37
  • @NutCracker It's only valid in C++20. Not all compilers have caught up yet. C++20 hasn't even been finalized . – NathanOliver Jan 28 '20 at 20:39
  • @NutCracker No problem. It is a needed addition to try and make uniform initialization more uniform. – NathanOliver Jan 28 '20 at 20:42
5

In addition to other answers, from here:

void - type with an empty set of values. It is an incomplete type that cannot be completed (consequently, objects of type void are disallowed). There are no arrays of void, nor references to void. However, pointers to void and functions returning type void (procedures in other languages) are permitted.

This means that you can initialize your void type to any value a == b ? foo() : void(1) or a == b ? foo() : void(1111) but it will perform nothing and would still compile successfully.

NutCracker
  • 11,485
  • 4
  • 44
  • 68