Program being compiled differently in 3 major C++ compilers. Which one is right?
C++Language LawyerC++ 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);
}
-
Compiling with g++ 4.9.2 gives me the following compilation error:
main.cpp:16:10: error: cannot call constructor 'C::C' directly [-fpermissive]
-
It compiles successfully with MSVC2013/2015 and prints
C (B *)
-
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.