C++找不到继承自当前模板类的模板基类中定义的类型

Dim*_*nov 2 c++ templates super crtp typename

我正在尝试编写定义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;
}
Run Code Online (Sandbox Code Playgroud)

如果我不需要New参数,我也可以使用Inherit模板,但我真的需要New.我可以通过使用选项来编译代码,D但这会破坏整个目的.

我有两个问题:

  1. 究竟是什么语言问题阻止类名Super 在类中被知道Template,为什么在这种NonTemplate情况下有所不同?
  2. 有没有人有想法解决这个问题的好方法?

Tar*_*ama 6

问题是它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>()));
Run Code Online (Sandbox Code Playgroud)

这使得使用更加简单:

template<class T>
struct Template : Inherit<Template<T>, SomeBase>
{
    using D = Super<Template>;
};
Run Code Online (Sandbox Code Playgroud)

如果您发现自己需要多个基类,可以概括它:

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>;
};
Run Code Online (Sandbox Code Playgroud)