0

The following code compiles fine under GCC and MSVC:

#include <string>

class C
{
public:
   C(const std::string&) { }
};

void f()
{
    std::string s;
    const std::string& sr = s;
    C c = C(sr);
}

Furthermore, if I replace that (entire) last line with this, both compilers accept it:

(C(sr));

However, if I replace that last line with this:

C(sr);

Compilers report the following:

GCC:

$ c++ --std=c++17 yo.cpp
yo.cpp: In function ‘void f()’:
yo.cpp:13:9: error: conflicting declaration ‘C sr’
C(sr);
^
yo.cpp:12:24: note: previous declaration as ‘const string& sr’
const std::string& sr = s;

MSVC:

cl /std:c++17 Source.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.16.27043 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
Source.cpp
C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.16.27023\include\xlocale(319): warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
Source.cpp(14): error C2040: 'sr': 'C' differs in levels of indirection from 'const std::string &'
Source.cpp(14): error C2512: 'C': no appropriate default constructor available
Source.cpp(3): note: see declaration of 'C'

Keith Russell
  • 560
  • 4
  • 12
  • 9
    I'm not sure what you mean. This has never compiled in c++. And `C(sr)` is not a constructor call, it's actually as if you wrote `C sr;`. Now you can see that it's a redeclaration, which is not allowed. – cigien Oct 16 '20 at 20:43
  • @cigien, sorry, see my latest edits. I did a bit more experimenting after hitting submit. (Also removed the note about C++17 after double-checking it.) – Keith Russell Oct 16 '20 at 21:01
  • Yes, I see that. I've answered below. – cigien Oct 16 '20 at 21:02
  • The Slightly-Vexing Parse strikes again – M.M Oct 16 '20 at 21:05
  • @M.M, I can't find anything written about "Slightly Vexing Parse" anywhere. Is this name just oral tradition? I'd like to read more about it. – Keith Russell Oct 16 '20 at 21:21
  • 1
    It's a play on "Most Vexing Parse" :) It's not an official term, it's used to describe situations such as this, where human beings see some code, and it *obviously* means something to them, but the compiler disagrees. There are a few examples of this nature, and depending on your familiarity with c++, they may be more or less vexing for you :) – cigien Oct 16 '20 at 22:36

1 Answers1

4

This statement:

C(sr);

is not calling a constructor. The syntax is actually a declaration of a variable named sr of type C, with additional redundant parentheses around the declarator sr.

Since sr has already been declared, you get an error.

On the other hand, in this statement:

(C(sr));

the expression C(sr) is actually parsed as the initialization of a C object, where sr is passed as an argument. The temporary C object that gets created is then destroyed at the end of the full expression.

cigien
  • 57,834
  • 11
  • 73
  • 112
  • `C{sr};` is another option. Technically it's not a constructor call, it's a request for creation of an object which may involve the constructor being called. (e.g. in C++20 if `C` were an aggregate, then `(C(sr));` proceeds with aggregate initialization and there is no constructor call) – M.M Oct 16 '20 at 21:01
  • I don't hate many things about C++. I now hate this. – Keith Russell Oct 16 '20 at 21:03
  • @KeithRussell I'm sorry to hear that, it is an unfortunate syntactical oddity. fwiw, use `{}` for objects, and `()` for function calls, and that'll reduce the chances of making these mistakes :) – cigien Oct 16 '20 at 21:06
  • 1
    @cigien until we get to objects where list initialization has different behaviour to parenthesized initialization from the same arguments... (e.g. `std::vector`) – M.M Oct 16 '20 at 21:07
  • 1
    @M.M Yes, but I think adding that to the answer would be a digression, and not very useful to explain the parsing issue. Is the edit better? – cigien Oct 16 '20 at 21:09
  • What ever was the use of allowing/ignoring parenthesis around the names of variables in declarations, I wonder? – Keith Russell Oct 16 '20 at 21:13
  • 1
    @KeithRussell See https://stackoverflow.com/questions/29675601/why-does-c-allow-us-to-surround-the-variable-name-in-parentheses-when-declarin – cigien Oct 16 '20 at 21:14
  • Ah, thanks. So, it's to support the other awkward element of C declaration syntax: function pointers. I wonder if there was a design choice they coulda made at the beginning to avoid both of these in one stroke. – Keith Russell Oct 17 '20 at 02:59