5

In my attempt to learn C++'s const correctness in combination with move semantics, I ended up with the following code.

MRE:

#include <iostream>
class ThisReference
{
    public:
    void f() const && { std::cout << "f() const &&\n"; }
};

int main()
{
    (const ThisReference){}.f();
}

Godbolt [a little bit longer with all method candidates]

That code compiles with GCC and I thought I understood what it means, i.e.:

  1. (const ThisReference) defines the type. I wanted it to be const, so I put that into parens.
  2. {} does the initialization of that type; creates an object
  3. .f() calls the method
  4. ; ends the statement

Eventually I put that code into Visual Studio and it didn't compile. The error message is

error C4576: a parenthesized type followed by an initializer list is a non-standard explicit type conversion syntax

I have 2 questions about my code.

  1. Which non-standard GCC feature am I using here and how would I turn it off?
  2. Something in my thinking is probably wrong. What is wrong?
Thomas Weller
  • 55,411
  • 20
  • 125
  • 222
  • IMHO it's not really worth asking the two questions in 2 posts separately. If you feel I should create a copy of the post and just ask a different question at the end, let me know. – Thomas Weller Jun 14 '23 at 08:52
  • It's not about GCC. It's about the language. Your question doesn't make sense as stated. – user207421 Jun 14 '23 at 10:35
  • @user207421: IMHO it's something about GCC where GCC treats the language in a different way than other compilers. At least the accepted answer fits perfectly for me, because it tells me what the construct is, why GCC compiles it and why MSVC doesn't compile it. In what way doesn't my question make sense? – Thomas Weller Jun 14 '23 at 10:40

1 Answers1

8
(const ThisReference) {}

This is a compound literal, and it's a C99 feature, not a C++ feature.

GCC compiles this code because it supports compound literals as a non-standard extension. You can disallow this by adding -Wpedantic -Werror to your compiler flags, or just -Werror=pedantic:

<source>: In function 'int main()':
<source>:10:27: error: ISO C++ forbids compound-literals [-Werror=pedantic]
   10 |     (const ThisReference){}.f();
      | 

See live demo

The reason why MSVC (Microsoft Visual Studio Compiler) gives you that error message is that it thinks {} is list initialization, and (const ThisReference) is a C-style cast, and these two can't appear together in C++ normally.


See also: Are compound literals Standard C++?

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
  • 2
    To add: You can achieve this in C++ with a type alias: `using ThisConstRef = const ThisReference; ThisConstRef{}.f();` – perivesta Jun 14 '23 at 09:06
  • @perivesta: that's a nice solution. It prevents me from creating an otherwise useless method that returns a `const ThisReference`. – Thomas Weller Jun 14 '23 at 09:33
  • @perivesta It is not the same. The lifetime (temporary vs block-scope) and value category (rvalue vs lvalue) are different. The difference is probably why this will never be a unified feature between C and C++. Although I guess what OP wants here is actually the C++ behavior for `ThisConstRef{}`, not the C behavior. – user17732522 Jun 14 '23 at 22:04
  • @ThomasWeller `const &&` is not really useful for anything. The only uses I know for `const &&`-qualification are to specifically delete such an overload in order to disallow the function to be called with rvalue arguments. I don't see any possible use case for the example in your question. – user17732522 Jun 14 '23 at 22:10
  • @user17732522: that might be true. I am learning this stuff from scratch right now. At the moment I am figuring out what is syntactically possible. I'll then go into the semantics and figure out what it means and what it could be useful for. I want to end up with a list of useful stuff, a list of maybe sometimes in special situations stuff and a list of stuff that is nonsense. – Thomas Weller Jun 15 '23 at 06:32
  • @user17732522: you are right. I want the behavior described by perivesta and not some C behavior. I didn't even think this could be C behavior, because I compiled it as C++. But yeah, ... learning something every day :-) – Thomas Weller Jun 15 '23 at 06:36