Program being compiled differently in 3 major C++ compilers. Which one is right?

C++Language Lawyer

C++ Problem Overview


As an interesting follow-up (not of big practical importance though) to my previous question: https://stackoverflow.com/questions/29675601/why-does-c-allow-us-to-surround-the-variable-name-in-parentheses-when-declarin

I found out that combining the declaration in parentheses with injected class name feature may lead to surprising results regarding compiler behavior.

Take a look at the following program:

#include <iostream>
struct B
{
};

struct C
{
  C (){ std::cout << "C" << '\n'; }
  C (B *) { std::cout << "C (B *)" << '\n';}
};

B *y = nullptr;
int main()
{
  C::C (y);
}
  1. Compiling with g++ 4.9.2 gives me the following compilation error:

     main.cpp:16:10: error: cannot call constructor 'C::C' directly [-fpermissive]
    
  2. It compiles successfully with MSVC2013/2015 and prints C (B *)

  3. It compiles successfully with clang 3.5 and prints C

So obligatory question is which one is right? :)

(I strongly swayed towards clang version though and msvc way to stop declaring variable after just changing type with technically its typedef seems kind of weird)

C++ Solutions


Solution 1 - C++

GCC is correct, at least according to C++11 lookup rules. 3.4.3.1 [class.qual]/2 specifies that, if the nested name specifier is the same as the class name, it refers to the constructor not the injected class name. It gives examples:

B::A ba;           // object of type A
A::A a;            // error, A::A is not a type name
struct A::A a2;    // object of type A

It looks like MSVC misinterprets it as function-style cast expression creating a temporary C with y as a constructor parameter; and Clang misinterprets it as a declaration of a variable called y of type C.

Solution 2 - C++

G++ is correct as it gives an error. Because the constructor could not be called directly in such a format without new operator. And although your code calls C::C, it looks like an constructor call. However, according to the C++11 standard 3.4.3.1, this is not a legal function call, or a type name (see Mike Seymour's answer).

Clang is wrong since it even does not call the correct function.

MSVC is something reasonable, but still it does not follow the standard.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPredelnikView Question on Stackoverflow
Solution 1 - C++Mike SeymourView Answer on Stackoverflow
Solution 2 - C++Kun LingView Answer on Stackoverflow