C ++ не может найти тип, определенный в базовом классе шаблона, который наследуется от текущего класса шаблона

Я пытаюсь написать вариант класс шаблона, определяющий super тип идиома. Класс Inherit вводит тип Super чтобы обозначить, возможно, очень длинный супер тип, а также необходимо знать производный тип New сделать некоторые дополнительные вещи, которые я не показываю здесь.

Это прекрасно работает, если тип передан New не шаблон, но не работает с шаблонами. Вот полный пример, скомпилированный с clang++-3.8 -std=c++1y -Wall (gcc выдает тот же результат):

struct SomeBase {};

template<class New, class Base>
struct Inherit : Base {
using Super = Inherit<New, Base>;
};

struct NonTemplate : Inherit<NonTemplate, SomeBase> {
using X = Super;
// compiles and is nice and short
};

template<class T>
struct Template : Inherit<Template<T>, SomeBase>
{
using A = Super;
// error: unknown type name 'Super'; did you mean 'NonTemplate::Super'?

using B = typename Super;
// error: expected a qualified name after 'typename'

using C = Inherit::Super;
// error: 'Inherit' is not a class, namespace, or enumeration

using D = typename Inherit<Template<T>, SomeBase>::Super;
// compiles, but what's the point?
};

int main() {
return 0;
}

Если мне не нужно New параметр, который я также могу использовать Inherit с шаблонами, но мне очень нужно New, Я мог бы сделать код с помощью опции D но это побеждает всю цель.

У меня есть два вопроса:

  1. Что именно является языковой проблемой, которая мешает имени типа Super
    быть известным в классе Template и почему это отличается в NonTemplate дело?
  2. У кого-нибудь есть идея для хорошего решения этой проблемы?

2

Решение

Проблема в том, что Inherit<Template<T>, SomeBase> это зависимый базовый класс, то есть класс зависит от параметра шаблона. Имена в зависимом базовом классе скрыты от неквалифицированного поиска, поэтому вам нужно уточнять имя.

typename необходимо, потому что Inherit<Template<T>, SomeBase>::Super является зависимым именем, и компилятор должен сообщить ему, что он называет тип, так как он может быть определен только во время создания экземпляра.

Увидеть Где и почему я должен поставить ключевые слова «template» и «typename»? для углубленного объяснения typename ключевое слово.


Что касается решений, вы могли бы учитывать Super в черту типа:

template<class New, class Base>
struct Inherit : Base {
};

namespace detail {
template <class New, class Base>
Inherit<New,Base> Super (const Inherit<New, Base>&);
}
template <class T>
using Super = decltype(detail::Super(std::declval<T>()));

Это делает использование намного проще:

template<class T>
struct Template : Inherit<Template<T>, SomeBase>
{
using D = Super<Template>;
};

Если вам нужно это для нескольких базовых классов, вы можете обобщить это:

namespace detail {
template <template <typename...> class T, class... Args>
T<Args...> Super (const T<Args...>&);
}
template <template <typename...> class Base, class Derived>
using Super = decltype(detail::Super<Base>(std::declval<Derived>()));

template <typename T>
using InheritSuper = Super<Inherit,T>;

template<class T>
struct Template : Inherit<Template<T>, SomeBase>
{
using D = InheritSuper<Template>;
};
6

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]