1

Consider the following code:

void foo() { return void(); }
void bar() { return void{}; }

foo() compiles, but bar() doesn't (using GCC 8.2 and clang 7.0 on GodBolt).

Why?

einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • 1
    Because it is invalid syntax. Not sure why `void()` works. Would you ever actually write code like this? – Robert Harvey Dec 14 '18 at 17:21
  • 2
    Related [How much existing C++ code would break if void was actually defined as `struct void {};`](https://stackoverflow.com/q/53197340/1708801) – Shafik Yaghmour Dec 14 '18 at 17:21
  • 1
    Templated code that returns `T{};`? – Matthieu Brucher Dec 14 '18 at 17:21
  • Ah. Yeah, that makes sense (if it actually worked). – Robert Harvey Dec 14 '18 at 17:22
  • 3
    The related question that @ShafikYaghmour linked is a surprisingly complete answer to your question. – Robert Harvey Dec 14 '18 at 17:23
  • 1
    `void()` could be parsed as a C-style cast of an empty expression. Is that valid? – John Dec 14 '18 at 17:27
  • +1 for Robert Harvey's comment that actually made me read the +1 link in Shafik Yaghmour's comment. Fun and informative with the lovely ingress "_void is a bizarre wart in the C++ type system_". – Ted Lyngmo Dec 14 '18 at 17:35
  • @RobertHarvey: I don't see how. My question is about what I would consider a missing piece of syntactic sugar. – einpoklum Dec 14 '18 at 17:35
  • 2
    @John: Firstly, `void()` is a functional cast, not C-style cast. Secondly, uniform `void` in generic code is an important idiom in C++. It is surprising that someone finds this strange. – AnT stands with Russia Dec 14 '18 at 17:36
  • Clang sees a `CXXScalarValueInitExpr` in `return void();`, not a `CXXFunctionalCastExpr`. https://godbolt.org/z/gDlPj3 vs https://godbolt.org/z/--fPuE. – Max Langhof Dec 14 '18 at 17:42
  • 1
    Direct dupe of https://stackoverflow.com/q/46979441 – Baum mit Augen Dec 14 '18 at 17:43
  • @BaummitAugen it might answer it but it dupped badly because they dup it is linked to does not really answer this question. – Shafik Yaghmour Dec 14 '18 at 17:48
  • @ShafikYaghmour The question I linked of course does not answer the question, as it is an unanswered question. It surely is the same question though IMO. Now that that question's dupe target isn't great, I would agree. – Baum mit Augen Dec 14 '18 at 17:49
  • One example more proving that uniform initialisation (as is now) was a ***big*** mistake added to the language... – Aconcagua Dec 14 '18 at 17:49
  • @Aconcagua [Want some more](https://www.youtube.com/watch?v=7DTlWPgX6zs)? – NathanOliver Dec 14 '18 at 17:59
  • @NathanOliver And I thought I had seen far enough already before, interesting enough, found my favourite sentence in: "Uniform initialization increases the mess." – Aconcagua Dec 14 '18 at 19:30
  • @Aconcagua Unfortunately they decided not to break backwards compatibility. I get why they decided that, but it has made something that should be easy a lot more difficult. Throw in generic code and now you really have to pay attention. Hopefully they'll figure out a way to fix it. With the 3 year release cycle they are trying to maintain hopefully it wont be too long before it is fixed. – NathanOliver Dec 14 '18 at 19:37
  • @NathanOliver: Yeah, by 2026 C++ will probably be a great language, and by 2032 or so the libraries will have caught up as well :-) ha-ha-only-serious... – einpoklum Dec 15 '18 at 00:01
  • @NathanOliver It's what in German would be called a 'Schnellschuss' - there are just too many issues with. One of my favourites: `std::vector v{7}`; I *always* use parentheses: `v(7)` vs. `v({7})`, so everything clear. If `v{{7}}` had been mandatory for using initialiser lists (that one per se is a *great(!!!)* feature, by the way), and the other issues I discovered so far handled appropriately as well (please don't ask me now which ones, there *were* others, but I don't remember now...), then I'd need to start asking myself if I just was trying to preserve old habits. But as is *now*... – Aconcagua Dec 15 '18 at 06:38

1 Answers1

2

void is an incomplete type. Since it is an incomplete type the expression void{} is illegal.

void() however is granted an exception in [expr.type.conv]/2

[...] If the type is cv void and the initializer is (), the expression is a prvalue of the specified type that performs no initialization. [...]

Which can be/is useful in generic code.


There is an active issue on this and the current proposed wording for the C++20 draft is

[...] 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. [...]

Which will allow you to do return void{}; if it is accepted.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • I really like the second part of your answer! – einpoklum Dec 14 '18 at 18:10
  • @einpoklum Glad you liked it. Hopefully compilers it will be adopted in and compilers get it added soon. – NathanOliver Dec 14 '18 at 18:13
  • Alternatively you could say it is not an object which is what all the language in `[dcl.init.list]` uses. Also if the defect does not get accepted then we have to wait for "Regular Void" – Shafik Yaghmour Dec 14 '18 at 18:25
  • @ShafikYaghmour: I just added an answer to the [question you linked to](https://stackoverflow.com/q/53197340/1708801) earlier, explaining why I'm against `regular void` (at least the way the question presents it). – einpoklum Dec 14 '18 at 19:10