Injected class names: The C++ feature you didn’t even realize that you were using

Raymond Chen

C++ has a feature called injected class names, which lets you refer to the class being defined by its plain name without needing to fully qualify it with namespaces and template parameters.

You have probably been taking advantage of this feature without even realizing it:

template<typename T>
struct Wrapper
{
    Wrapper() { /* constructor */ }
};

That Wrapper() is using the injected class name. The full name of the constructor is

    Wrapper<T>() { /* constructor */ }

but C++ secretly injects the simple name of the class into the class itself, as if you had written

    using Wrapper = Wrapper<T>;

Injected class names are public and therefore can be inherited:

namespace details {
    struct Base
    {
        Base(int) { /* constructor */ }
    };
}

struct Derived : details::Base
{
    Derived() : Base(42) { /* constructor */ }
};

The construction of the base class from the derived class can be done by writing just Base(42) instead of the full name details::Base(42). The injection goes like this:

namespace details {
    struct Base
    {
        using Base = ::details::Base; // injected
        Base(int) { /* constructor */ }
    };
}

struct Derived : details::Base
{
    Derived() : Base(42) { /* constructor */ }
}

When you write Base inside the definition of Derived, you are using the name Base that was defined way over there in the Base class.

Note that making base classes private prevents their types from being inherited:

namespace details {
    struct Base { };
    struct Middle : private Base { };
}

struct Derived : details::Middle
{
    void blah()
    {
        Middle m; // "Middle" accessible from details::Middle
        Base b; // "Base" not accessible because it was privately inherited
        details::Base b; // Need to use the full name
    }
};

1 comment

Discussion is closed. Login to edit/delete existing comments.

  • 紅樓鍮 0

    Injected class names are public and therefore can be inherited

    Unfortunately those names aren’t useful if your base classes are dependent (on template parameters), since you have to qualify them with the specific base class they’re from if you want to refer to them, which in this case defeats the purpose of injected class names completely. This frustration is especially frequently encountered when one uses CRTP.

    Bonus chatter: I’d actually like the injected class names to be protected rather than public; I don’t think I’ve ever had a use of injected class names from outside the class hierarchy.

Feedback usabilla icon