Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"names the constructor, not the type" in G++ 4.4.7

Tags:

c++

gcc

I have the following simple C++ code:

#include <cstdio>

class A
{
public:
    A(int y) : x(y) {}
    A& operator=(const A& rhs);
    int x;
};

A::A& A::operator=(const A& rhs) { this->x = rhs.x; return *this; }

int main(int, char**)
{
    A a1(5);
    A a2(4);

    printf("a2.x == %d\n", a2.x);

    a2 = a1;

    printf("a2.x == %d\n", a2.x);

    return 0;
}

Line 11, where the definition of A's operator=() function is at, is malformed...or, at least, I believe so. As expected, G++ 4.7.4, as well as every newer version of GCC that I've tried, throws the following error:

main.cpp:11:1: error: ‘A::A’ names the constructor, not the type

Oddly, though, G++ 4.4.7 compiles this program successfully, with no warnings, and even prints 4 and 5 as would be expected if line 11 were written correctly (i.e. with just A& instead of A::A&).

Can someone help me decipher what exactly is going on there with G++ 4.4.7? Is this just a bug in that release (albeit an extremely old one, and shame on us for still using it)? I'd think the standard would explicitly state how the operator=() function must be declared and defined.

like image 451
villapx Avatar asked May 31 '17 22:05

villapx


2 Answers

There was a related bug in g++. It was fixed in version 4.5.0, so 4.4.7 still has it.

Here is the bug description:

cc1plus does not implement the class name injection correctly. In particular the snipped below should be rejected on the basis that A::A does not name a type (it designates a constructor)

struct A { };

int main()
{
    A::A a;       // should be an ERROR
}

Although the symptoms of this bug are not identical to what you describe, in both cases the compiler treats A::A as a type name, when it actually names a constructor. I am pretty certain that the two behaviors have the same root cause, which is poor implementation of scope resolution prior to version 4.5.0.

like image 95
Sergey Kalinichenko Avatar answered Nov 09 '22 18:11

Sergey Kalinichenko


Expanding on dasblinkenlight's correct answer--the C++03 standard explicitly outlaws his and my code in [class.qual]:

If the nested-name-specifier nominates a class C, and the name specified after the nested-name-specifier, when looked up in C, is the injected-class-name of C (clause 9), the name is instead considered to name the constructor of class C. Such a constructor name shall be used only in the declarator-id of a constructor definition that appears outside of the class definition. [Example:

struct A { A(); };
struct B: public A { B(); };

A::A() { }
B::B() { }

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

—end example]

like image 37
villapx Avatar answered Nov 09 '22 18:11

villapx