具有依赖qualified-id的类成员using声明是否应该是依赖名称?

时间:2014-11-26 20:58:06

标签: c++ templates language-lawyer using-declaration dependent-name

C ++ 11标准的N3337草案在[namespace.udecl]

中声明
  

using声明在声明区域中引入了一个名称,其中出现了using声明。

     

每个using声明都是声明和成员声明,​​因此可以在类定义中使用。

     

在用作成员声明的using声明中,nested-name-specifier应命名一个基类。   正在定义的类。

这通常用于在派生类的基类public中创建受保护的typedef,如下例所示,它在最新版本的Clang中成功编译:

struct A
{
protected:
    typedef int Type;
};

struct B : A
{
    using A::Type;
};

B::Type x;

using声明可以引用模板类。这编译:

struct A
{
protected:
    template<typename T>
    struct Type
    {
    };
};

struct B : A
{
    using A::Type;
};

B::Type<int> x;

也可以引用依赖基类中的模板。以下编译成功(使用typedef注释。)

template<typename T>
struct A
{
protected:
    template<typename U>
    struct Type
    {
    };
};


template<typename T>
struct B : A<T>
{
    using /* typename */ A<T>::Type; // A<T> is dependent, typename required?
    // typedef Type<int> IntType; // error: unknown type name 'Type'
};

B<int>::Type<int> x;

取消注释typename会在实例化B<int>时导致错误:&#34;错误:&#39; typename&#39;在非类型&#34;。

上使用的关键字

取消注释typedef会在第一次实例化之前解析B时导致错误。我猜这是因为编译器不会将Type视为依赖类型名称。

[namespace.udecl]的最后一段建议使用声明可以指定依赖名称,并且必须使用typename关键字才能消除对引入名称的进一步使用的歧义:

  

如果using声明使用关键字typename并指定依赖名称(14.6.2),则引入名称   by-declaration被视为typedef-name

我对[temp.dep]的解读表明A<T>::Type是一个从属名称。从逻辑上讲,using-declaration引入的名称也应该是依赖的,但[temp.dep]没有明确提到依赖using声明的情况。我错过了什么吗?

2 个答案:

答案 0 :(得分:2)

问题是Type不是类,而是类模板。您可以执行以下操作(这样您告诉编译器TypeB范围内的类模板:

template<typename T>
struct B : A<T>
{
    using A<T>::Type;
    typedef typename B::template Type<int> IntType;
};

实际上,在你的第二个例子中为了typedefIntType,你必须这样做。

答案 1 :(得分:0)

是的,具有依赖qualified-id的类成员using声明引入了依赖名称。

  

[namespace.udecl]

     

using声明在声明区域中引入了一个名称,其中出现了using声明。

如果引入的名称是依赖的,它仍然是依赖的 - 我找不到任何其他建议。

但是,using-declaration语法不提供指定依赖名称是模板的方法。对Type中的从属名称B的后续引用可能会或可能不会引用模板,因此无法解析Type<int>

以下示例演示了依赖的using声明的有效用法。

template<typename T>
struct A
{
protected:
    struct Type
    {
        typedef int M;
    };
};


template<typename T>
struct B : A<T>
{
    using typename A<T>::Type;
    typedef typename Type::M Type2;
};

B<int>::Type2 x;