嵌套中的模板别名可见性 class

Template alias visibility in nested class

考虑以下几点:

template<typename X>
struct Z {};

struct A
{
    using Z = ::Z<int>;

    struct B : Z
    {
        using C = Z;
    };
};

这编译得很好。好的。但是现在在 Z 中添加另一个参数:

template<typename X, typename Y>
struct Z {};

struct A
{
    template<typename X>
    using Z = ::Z<X, int>;

    struct B : Z<B>
    {
        using C = Z<B>;  // error: too few template arguments for class template 'Z'
    };
};

好吧,也许在派生嵌套classB时可见classA中模板别名Z的定义是有道理的,但是不在它的体内,触发错误,因为 Z 的全局定义有两个参数。

但是 为什么 在第一种情况下行为不同,当 Z 只是 A 中的类型别名时?

最后,制作A模板:

template<typename X, typename Y>
struct Z {};

template<typename T>
struct A
{
    template<typename X>
    using Z = ::Z<X, int>;

    struct B : Z<B>
    {
        using C = Z<B>;
    };
};

现在错误消失了。 为什么?

(在 Clang 3.6 和 GCC 4.9.2 上测试)

简而言之:派生自 Z 的特化引入 injected-class-name of ::Z,这是在之前找到的别名模板。但是,如果 A 是一个模板,则不再找到 injected-class-name,因为 B 的基础 class是依赖的。


考虑 [temp.local]/1:

Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injected-class-name can be used as a template-name or a type-name.

和[basic.lookup]/3:

The injected-class-name of a class (Clause 9) is also considered to be a member of that class for the purposes of name […] lookup.

Z 被查找为不合格的名称; [basic.lookup.unqual]/7:

因此,injected-class-name Z 被发现是 base class Z<B, int> 的成员, 并用作 模板名称 ,这会导致您的第二个程序格式错误。事实上,您的第一个代码段也使用 injected-class-name - 以下代码段无法编译:

struct A
{
    using Z = ::Z<float>;
    struct B : ::Z<int>
    {
        static_assert( std::is_same<Z, ::Z<float>>{}, "" );
    };
};

最后,如果 A 是一个模板,请注意 B 是一个依赖类型,根据 [temp.dep.type]/(9.3)1,因此 Z<B> 是根据 [temp.dep.type]/(9.7) 的依赖类型,因此 base class Z<B> 在期间不检查根据 [temp.dep]/3:

查找 unqualified-id Z

In the definition of a class [..], the scope of a dependent base class (14.6.2.1) is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member.

因此 注入的-class-名称 将找不到。


1 B 是 "nested class [..] that is a dependent member of the current instantiation"(强调我的),因为

A name is a dependent member of the current instantiation if it is a member of the current instantiation that, when looked up, refers to at least one member of a class that is the current instantiation.