C++ 嵌套类中的模板别名可见性

C++ 嵌套类中的模板别名可见性,c++,c++11,language-lawyer,nested-class,template-aliases,C++,C++11,Language Lawyer,Nested Class,Template Aliases,考虑以下几点: template<typename X> struct Z {}; struct A { using Z = ::Z<int>; struct B : Z { using C = Z; }; }; 好的,在类A中的模板别名Z的定义在派生嵌套类B时可见,但在其主体内部不可见,这可能会触发错误,因为Z的全局定义有两个参数 但是当Z只是a中的一个类型别名时,为什么在第一种情况下行为有所不同 最后,制作AA模板

考虑以下几点:

template<typename X>
struct Z {};

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

    struct B : Z
    {
        using C = Z;
    };
};
好的,在类
A
中的模板别名
Z
的定义在派生嵌套类
B
时可见,但在其主体内部不可见,这可能会触发错误,因为
Z
的全局定义有两个参数

但是
Z
只是
a
中的一个类型别名时,为什么在第一种情况下行为有所不同

最后,制作
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>;
    };
};
模板
结构Z{};
模板
结构A
{
模板
使用Z=::Z;
结构B:Z
{
使用C=Z;
};
};
现在错误消失了为什么?


(在Clang 3.6和GCC 4.9.2上测试)

简言之:源自
Z
的专门化,引入了注入的类名称
::Z
,它位于别名模板之前。但是,如果
A
是模板,则不会再找到注入的类名,因为
B
的基类是依赖的


考虑[temp.local]/1:

与普通(非模板)类一样,类模板具有 注入类名称(第9条)可以使用注入的类名 作为模板名或类型名

和[basic.lookup]/3:

出于名称[…]查找的目的,类的注入类名(第9条)也被视为该类的成员

Z
作为非限定名称查找;[basic.lookup.unqual]/7:

因此,注入的类名
Z
被发现为基类
Z
的一个成员,并用作模板名,这会导致第二个程序格式错误。事实上,您的第一个代码段也使用了注入的类名-以下代码段不会编译:

struct A
{
    using Z = ::Z<float>;
    struct B : ::Z<int>
    {
        static_assert( std::is_same<Z, ::Z<float>>{}, "" );
    };
};
结构A { 使用Z=::Z; 结构B:::Z { 静态断言(std::is_same{},“”; }; }; 最后,如果将
A
作为模板,请注意
B
根据[temp.dep.type]/(9.3)1是一个依赖类型,因此
Z
根据[temp.dep.type]/(9.7)是一个依赖类型,因此在根据[temp.dep]/3查找不合格id时不会检查基类
Z

在类[…]的定义中 不合格试验期间未检查相关基类(14.6.2.1) 在类模板的定义点或 成员或在类模板或成员的实例化过程中

因此,将找不到注入的类名


1
B
是一个“嵌套类[…],它是当前实例化的依赖成员”(emphasis mine),因为

名称是当前实例化的从属成员(如果它是 当前实例化的成员,在查找时引用 作为当前实例化的类的至少一个成员


哇!这很清楚,谢谢。当
A
不再是一个模板时,这个错误就出现了,我认为这会大大简化代码。然而,我现在不得不为这两个
Z
使用两个不同的名称,这只会使代码更难看。如果有更好的解决方法,请告诉我。@iavr使用C=Z的
如何?(不适用于
A
作为模板)现在这令人印象深刻:-)是的,它适用于这里的简化代码,但不适用于我的原始代码(
未知类型名称“Z”
)。我得检查一下区别在哪里<代码>A
不再是一个模板,我打算保持这种方式。啊,这是因为我已经重命名了外部的
Z
(比如,到
Z1
)。现在它工作起来了,而且非常简单,因为我根本不需要
使用C…
。太好了,再次感谢!
struct A
{
    using Z = ::Z<float>;
    struct B : ::Z<int>
    {
        static_assert( std::is_same<Z, ::Z<float>>{}, "" );
    };
};