首页 文章

具有依赖qualified-id的class-member using-declaration应该是依赖名吗?

提问于
浏览
7

C 11标准的N3337草案于 [namespace.udecl] 中声明

using声明在声明区域中引入了一个名称,其中出现using声明 . 每个using声明都是声明和成员声明,因此可以在类定义中使用 . 在用作成员声明的using声明中,嵌套名称说明符应命名要定义的类的基类 .

这通常用于在派生类的基类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> :"error: 'typename' keyword used on a non-type"时导致错误 .

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

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

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

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

2 回答

  • 0

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

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

    实际上,在你的第二个例子中为 typedeftypedef 你必须做同样的事情 .

  • 2

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

    [namespace.udecl] using声明在声明区域中引入了一个名称,其中出现using声明 .

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

    但是,using-declaration语法不提供指定依赖名称是模板的方法 . 对 B 中的从属名称 Type 的后续引用可能会也可能不会引用模板,因此无法解析 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;
    

相关问题