14

The other day, I discovered that this was possible:

template <class T> struct base {};
struct derived: base<int> {};

int main()
{
    // The base class template is accessible here
    typename derived::base<double> x;

    // from the comments, even this works
    typename derived::derived::base<double>::base<int>::base<void> y;
}

I have no recollection of ever reading this on cppreference or in C++ tutorials, or this being exploited in clever template metaprogramming tricks (because I'm sure it can be). I have several questions:

  • Does this thing have a specific name?
  • Where is it documented in the C++ standard and on cppreference?
  • Is there any template metaprogramming trick exploiting this?
cpplearner
  • 13,776
  • 2
  • 47
  • 72
Vincent
  • 57,703
  • 61
  • 205
  • 388
  • 8
    Note that `base` isn't a base class of `derived`. – François Andrieux Jan 15 '18 at 18:41
  • Not sure what you're trying to accomplish here? There's an irrelevant namespace on `base` and template type on `derived`. – Mark Ransom Jan 15 '18 at 18:43
  • 3
    @MarkRansom I don't think this is an attempt at accomplishing anything. Rather it's a curious observation. Where you would expect to need to qualify `base` with the namespace `space`, in this example using `derived` seems to accomplish the same thing. – François Andrieux Jan 15 '18 at 18:44
  • People are essentially accessing some nested type when using stuff like `std::enable_if<>::type`. Same thing. Upd: not only base, but self class is also accessible: so you can write like `typename derived::derived::derived::derived::base::base::base::base x;` – user7860670 Jan 15 '18 at 18:45
  • 2
    @MarkRansom Yeah, I'm not trying to accomplish anything (yet :p). It just seems very weird to me... – Vincent Jan 15 '18 at 18:47
  • 1
    Possible duplicate of [What does C++ syntax “A::B:A {};” mean](https://stackoverflow.com/questions/47546616/what-does-c-syntax-aba-mean) – user7860670 Jan 15 '18 at 19:02
  • 1
    Isn't this a dupe? I feel like the fact at least that the `derived` can be repeated has been discussed multiple times on SO. – Nir Friedman Jan 15 '18 at 19:02
  • @NirFriedman That's not really the point of the question though. – Rakete1111 Jan 15 '18 at 19:05
  • 4
    FYI, clang gives the following warning, which makes me think this isn't legal c++: `:7:57: warning: ISO C++ specifies that qualified reference to 'base' is a constructor name rather than a template name in this context, despite preceding 'typename' keyword [-Winjected-class-name] typename derived::derived::base::base::base x;` with an arrow pointing at the start of the last `base`. – Nir Friedman Jan 15 '18 at 19:07
  • @NirFriedman Only on Clang 5.0 and above (Clang 4.x does not give any warning). Hopefully other compilers fix this soon. – Alex Huszagh Jan 15 '18 at 19:15
  • 4
    The simpler version seems to throw out some of the utility here, in that `base` is no longer in a remote namespace. – Yakk - Adam Nevraumont Jan 15 '18 at 19:27
  • 3
    [\[temp.local\]](http://eel.is/c++draft/temp.local), [\[class.qual\]/2](http://eel.is/c++draft/class.qual#2) – cpplearner Jan 15 '18 at 19:29
  • @cpplearner Why didn't you write an answer? – Rakete1111 Jan 15 '18 at 19:41
  • So you're surprised that the name `base` is defined in the context of `derived`? I never thought about it but it makes sense that it would be. What really surprises me is @NirFriedman's note that it names a constructor function and not a type; normally constructors can't be called by name. – Mark Ransom Jan 15 '18 at 20:05
  • @MarkRansom I don't know what's going on here, the rabbit hole seems pretty deep to me: https://godbolt.org/g/N2PFv6. – Nir Friedman Jan 15 '18 at 20:46
  • @NirFriedman That warning is unjustified, because in a `typename` specifier, functions are ignored (IIRC). – Columbo Jan 18 '18 at 01:43

1 Answers1

5

As pointed out by @Nir Friedman in comment, typename derived::derived::base<double>::base<int>::base<void> y; might actually be ill-formed because derived::derived::base<double>::base<int>::base is treated as a constructor of base, per [class.qual]/2.


  • Does this thing have a specific name?

It is called injected-class-name.

  • Where is it documented in the C++ standard and on cppreference?

In the standard: [class]/2 specifies that the name of a class is treated as if it were a public member of that class. [temp.local] specifies that the injected-class-name of a class template can be used as either a template-name or a type-name.

On cppreference: it is (incompletely) documented in http://en.cppreference.com/w/cpp/language/unqualified_lookup#Injected_class_name.

  • Is there any template metaprogramming trick exploiting this?

I'm not aware of any such tricks, though in everyday use, injected-class-name is employed whenever the current class is named in the class definition:

template<class T>
struct A {
    A<T>& operator=(const A<T>&); // injected-class-name as template-name
    A& operator=(A&&); // injected-class-name as type-name
};

The latter may be deliberately used to shorten member declaration.

The injected-class-name of a base class is mostly used (unconsciously) in a member initializer list:

struct B : A<int> {
    B() : A() {}
};
cpplearner
  • 13,776
  • 2
  • 47
  • 72