简体   繁体   中英

C++ class function return type definition, return a class

I have a vector class look like this:

class Vector3
{

 public:
   Vector3(){m_x = m_y = m_z = 0.0f;}
   Vector3(const float & i_x, const float & i_y, const float & i_z):
     m_x(i_x), 
     m_y(i_y),
     m_z(i_z)
     {}

   Vector3 operator+(const Vector3 & i_other);
private:
   float m_x;
   float m_y;
   float m_z;
};

Vector3::Vector3 Vector3::operator+(const Vector3 & i_other)
{
   float tx = m_x + i_other.m_x;
   float ty = m_y + i_other.m_y;
   float tz = m_z + i_other.m_z;
   return Vector3(tx, ty, tz);
}

Obviously, the Vector3::operator+ definition synax is wrong because the return type is Vector3::Vector3 , not Vector3 . Vector3::Vector3 means there is a namespace Vector3 , and inside the name space there is a class Vector3 . But I only have a class Vector3 , no namespace here.

My question is, in Ubuntu 12.04, the syntax above can not be compiled (Ubuntu's g++ compiler is [gcc version 4.6.3]). However, in Mac, g++ can compile the code(Mac's g++ compiler is [gcc version 4.2.1]). Also, I test this syntax in a Red Hat linux machine, it also works (g++ version is [gcc version 4.4.6])

So, is it different version of gcc have different compile principle? Or, my g++ in Ubuntu broke?

The older compiler is incorrect. Little surprise there.

It is probably parsing Vector3::Vector3 as an injected-type-name. Inside the scope of class Vector3 { } , the identifier Vector3 refers to the class, not the constructor (except when you're declaring the constructor, of course). And at first glance, you might think it means the same thing in a return type, because §3.4/3 (I'm using the C++11 standard here) says

The injected-class-name of a class (Clause 9) is also considered to be a member of that class for the purposes of name hiding and lookup.

Digging deeper, in §3.4.3.1/2,

In a lookup in which the constructor is an acceptable lookup result and the nested-name-specifier nominates a class C:

— if 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.

The context of starting a declaration with an injected-class-name happens to be the same as in defining a constructor outside class {} scope, a la

class Vector3 { … };

Vector3::Vector3(){m_x = m_y = m_z = 0.0f;}

The older GCC noticed that the declaration wasn't a constructor, then took a fallback path that did work. However that fallback was illegal because C++ specifies that in a context where the constructor could be the result of the lookup, it is the only valid lookup result.

In all probability, some user took the time to file a bug, and a GCC developer took the time to diagnose this, fix it, and write a testcase. Multiply across the number of trivialities in a complex language like C++, and you start to appreciate the effort put into your compiler.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM