I had the following code, which was basically,
class foo {
public:
void method();
};
void foo::foo::method() { }
I had accidentally adde
Comeau online accepts it without any hickups, so it's either valid or the second bug in como I have found in almost ten years.
Is there a namespace foo in some other module that you include (and you were just ignorant of it)? Otherwise, it is not correct. I am not sure why g++ allowed this.
If I read the standard correctly, g++ is right and VS is wrong.
ISO-IEC 14882-2003(E), §9.2 Classes (pag.153): A class-name is inserted into the scope in which it is declared immediately after the class-name is seen. The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name. For purposes of access checking, the injected-class-name is treated as if it were a public member name.
Following on the comments below, it's also particularly useful to retain the following concerning the actual Name Lookup rules:
ISO-IEC 14882-2003(E), §3.4-3 Name Lookup (pag.29): 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.
It would be odd if it wasn't, given the final part of text at 9.2. But as litb commented this reassures us that indeed g++ is making a correct interpretation of the standard. No questions are left.
Krugar has the correct answer here. The name that is is being found each time is the injected class name.
The following is an example which shows at least one reason why the compiler adds the injected class name:
namespace NS
{
class B
{
// injected name B // #1
public:
void foo ();
};
int i; // #2
}
class B // #3
{
public:
void foo ();
};
int i; // #4
class A :: NS::B
{
public:
void bar ()
{
++i; // Lookup for 'i' searches scope of
// 'A', then in base 'NS::B' and
// finally in '::'. Finds #4
B & b = *this; // Lookup for 'B' searches scope of 'A'
// then in base 'NS::B' and finds #1
// the injected name 'B'.
}
};
Without the injected name the current lookup rules would eventually reach the enclosing scope of 'A' and would find '::B' and not 'NS::B'. We would therefore need to use "NS::B" everywhere in A when we wanted to refer to the base class.
Another place that injected names get used are with templates, where inside the class template, the injected name provides a mapping between the template name and the type:
template <typename T>
class A
{
// First injected name 'A<T>'
// Additional injected name 'A' maps to 'A<T>'
public:
void foo ()
{
// '::A' here is the template name
// 'A' is the type 'A<T>'
// 'A<T>' is also the type 'A<T>'
}
};