使用自己的类名来解析推导上下文中的类型

Jon*_*nas 13 c++ templates language-lawyer c++11

我使用我不熟悉的C++结构回答了这个问题.我想知道这是合法的还是g ++(6.3.0)和clang ++(3.5.0)都是错误的.该示例可在线获取:

#include <iostream>

template <typename T>
struct Base
{
    using Type = int;
};

template <typename T>
struct intermediate : Base<T>
{
    // 'Type' is not defined here, which is fine
};

template <typename T>
struct Derived : intermediate<T>
{
    using Type = typename Derived<T>::Type; // Is this legal?
//    using Type = typename intermediate<T>::Type; // Normal way of doing it
};

int main()
{
    Derived<void>::Type b = 1;
    std::cout << b << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

更新

正如评论中提到的(通过underscore_d)<T>Derived课堂上不是必需的.也就是说,这非常好:

using Type = typename Derived::Type;
Run Code Online (Sandbox Code Playgroud)

Ste*_*ner 7

我花了一段时间来理解(非常好的)问题,所以让我首先解释一下我是如何理解这一点的:

在模板级别,如果此基类模板依赖于模板参数(例如,参见此答案),则不会检查基类模板的范围.因此,using Type = int在类模板中使用模板参数声明的类型template <typename T> struct Base对于从此基类模板派生的类是不可见的template <typename T> struct intermediate : Base<T>,除非使用限定名称,即typename Base<T>::Type).

相反,在类级别,即使在没有限定名称的情况下使用这种类型声明也是可见的.因此,在实例化上述模板类时,在模板级别"不可见"的类型名称将在已实例化的类的级别上变得可见.

因此,如果模板级别的子类将定义与基类模板具有相同(非限定)名称的类型,则在模板级别上这将不明显.但是,在实例化模板时,这样的情况是否可能导致(可能不匹配)重新定义类型,因为基于非限定类型名称的两种类型定义可能在同一名称下可见?

正如nm所指出的那样,在他的评论中提供了这个引用,类型定义在模板定义的点上依赖于视图,即使在实例级别可以解析不同的类型:

在模板定义点查找并绑定非依赖名称.即使在模板实例化时存在更好的匹配,该绑定也成立.

因此,它实际上是合法的,因为这不会导致类型的无效重新定义.

但是,由于子类的类型定义实际上被视为一种新类型,它甚至可能以不同的方式定义,这可能并非意图:

template <typename T>
struct Base
{
    using Type = int;
};

template <typename T>
struct intermediate : Base<T>
{
    // 'Type' is not defined here, which is fine
};

template <typename T>
struct Derived : intermediate<T>
{
    //using Type = typename Derived<T>::Type; // legal.
    using Type = const char*; // Legal, too!
};

int main()
{
    Derived<void>::Type b = "OK, but is this actually intended?";
    std::cout << b << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

因此,子类不"继承",而是"覆盖"相应的类型.如果有人想"继承",那么应该写:

struct Derived : intermediate<T>
{
    using typename intermediate<T>::Type; // Inherits the type.
};
Run Code Online (Sandbox Code Playgroud)