Is void() a valid C++ expression? [duplicate]
Asked Answered
P

2

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?

Purgatory answered 28/1, 2020 at 20:17 Comment(9)
This is just someone trying to be smart. if(a==b){ foo(); } is clearer and has the same effect.Ravishment
@CássioRenan your version can't be used in an expression though .Tsimshian
@Tsimshian 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)Ravishment
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 callTsimshian
@Tsimshian you can't pass void() as an argument.Ravishment
@CássioRenan: Possible usage of void(): with SFINAE: template <typename T> 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)).Philately
@Philately 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.Ravishment
@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).Philately
What's the point of answering the same question so many times when we have duplicate system?Ger
A
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.

Arturoartus answered 28/1, 2020 at 20:22 Comment(3)
So, void{} should compile but it doesn't. According to this it should. But why it doesn't?Chloric
@Chloric It's only valid in C++20. Not all compilers have caught up yet. C++20 hasn't even been finalized .Arturoartus
@Chloric No problem. It is a needed addition to try and make uniform initialization more uniform.Arturoartus
C
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.

Chloric answered 28/1, 2020 at 20:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.