Я пытаюсь написать вариант класс шаблона, определяющий 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
но это побеждает всю цель.
У меня есть два вопроса:
Super
Template
и почему это отличается в NonTemplate
дело?Проблема в том, что 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>;
};
Других решений пока нет …