Why is there an injected class name?
Recently, I saw a strange C++ feature: injected class name.
class X { };
X x1;
class X::X x2; // class X::X is equal to X
class X::X::X x3; // ...and so on...
But I cannot figure out why this feature is necessary. Is there any practice that requires this feature?
And I heard this feature didn't exist in old C++. Then, when was it introduced? C++03? C++11?
Solution 1:
The injected class name means that X
is declared as a member of X
, so that name lookup inside X
always finds the current class, not another X
that might be declared at the same enclosing scope, e.g.
void X() { }
class X {
public:
static X create() { return X(); }
};
Is the create()
function creating a temporary X
object or calling the function X
? At namespace scope it would call the function, so the purpose of the injected-class-name is to ensure that within the body of X
the name always finds the class itself (because name lookup starts in the class' own scope before looking in the enclosing scope).
It's also helpful inside class templates, where the injected class name can be used without a template argument list, e.g. using simply Foo
instead of the full template-id Foo<blah, blah, blah>
, so it's easy to refer to the current instantiation. See DR 176 for a change between C++98 and C++03 that clarified that.
The idea of the injected class name was present in C++98, but the terminology was new for C++03.
C++98 says:
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.
The second sentence was changed by DR 147 so C++03 says in [class]/2:
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.
Even before C++98, the ARM has roughly equivalent wording that means the class' name can always be used in the class body to refer to the class itself:
The name of a class can be used as a class-name even within the member-list of the class specifier itself.
- For example,
class link { link* next; };