Подтвердить что ты не робот

Базовый класс шаблона доступен при наследовании по определенной специализации?

На днях я обнаружил, что это возможно:

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;
}

У меня нет воспоминаний о том, что вы когда-либо читали это на cppreference или в учебниках на С++, или это используется в умных трюках метапрограммирования шаблонов (потому что я уверен, что это может быть). У меня есть несколько вопросов:

  • У этой вещи есть определенное имя?
  • Где он задокументирован в стандарте С++ и на cppreference?
  • Есть ли какой-либо шаблонный метапрограммирующий трюк, использующий это?
4b9b3361

Ответ 1

Как отметил @Nir Friedman в comment, typename derived::derived::base<double>::base<int>::base<void> y; может быть плохо сформирован, потому что derived::derived::base<double>::base<int>::base рассматривается как конструктор base, per [class.qual]/2.


  • У этой вещи есть определенное имя?

Он называется injected-class-name.

  • Где он задокументирован в стандарте С++ и на cppreference?

В стандарте: [class]/2 указывает, что имя класса рассматривается так, как если бы он был публичным членом этого класс. [temp.local] указывает, что имя класса с добавленным именем шаблона класса может использоваться как имя шаблона, имя.

В cppreference: он (не полностью) задокументирован в http://en.cppreference.com/w/cpp/language/unqualified_lookup#Injected_class_name.

  • Есть ли какой-либо шаблонный метапрограммирующий трюк, использующий это?

Я не знаю о таких трюках, хотя в повседневном использовании имя injected-class-name используется всякий раз, когда текущий класс указан в определении класса:

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
};

Последнее может быть намеренно использовано для сокращения объявления участника.

Введенное имя класса базового класса в основном используется (бессознательно) в списке инициализаторов:

struct B : A<int> {
    B() : A() {}
};