【问题标题】:Should a class-member using-declaration with a dependent qualified-id be a dependent name?具有依赖限定 ID 的类成员 using-declaration 是否应该是依赖名称?
【发布时间】:2015-01-25 08:20:33
【问题描述】:

[namespace.udecl] 中的 C++11 标准状态草案 N3337

using-declaration 将名称引入到 using-declaration 出现的声明区域中。

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

在用作成员声明的 using-declaration 中,nested-name-specifier 应命名 类被定义。

这通常用于在派生类中使基类中的受保护类型定义为公共,如下例所示,该示例在最新版本的 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;

在实例化 B&lt;int&gt; 时取消注释 typename 会导致错误:“error: 'typename' keyword used on a non-type”。

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

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

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

我对@9​​87654331@ 的阅读表明A&lt;T&gt;::Type 是一个从属名称。从逻辑上讲,使用声明引入的名称也应该是依赖的,但[temp.dep] 没有明确提到依赖使用声明的情况。我错过了什么吗?

【问题讨论】:

  • 7.3.3p5: "using-declaration 不得命名 template-id"?

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


【解决方案1】:

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

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

实际上,在您的第二个示例中,要为IntType 编写typedef,您必须这样做。

【讨论】:

  • 正如 Anton 指出的(在编辑答案之前),复杂之处在于 using-declaration 语法没有提供一种方法来指定依赖名称是模板。后续使用B内的依赖名Type无法知道是模板,所以无法解析Type&lt;int&gt;
  • 这是一个看似有效的依赖 using 声明用法的好例子。假设依赖使用声明引入依赖名称似乎是安全的。
  • 根据 [temp.dep.type],附加限定 B:: 使 Type 成为“未知专业化的成员”:B::Type&lt;int&gt; 命名为依赖类型。
【解决方案2】:

是的,具有依赖限定 ID 的类成员 using-declaration 引入了依赖名称。

[命名空间.udecl]

using-declaration 将名称引入到 using-declaration 出现的声明性区域中。

如果引入的名称是依赖的,它会保持依赖 - 否则我找不到任何建议。

但是,using-declaration 语法没有提供一种方法来指定从属名称是一个模板。对 B 内的依赖名称 Type 的后续引用可能引用也可能不引用模板,因此无法解析 Type&lt;int&gt;

以下示例演示了依赖 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;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-02
    • 1970-01-01
    相关资源
    最近更新 更多