【问题标题】:When can `typename` be used with identifiers that unambiguously refer to a type?什么时候可以将 `typename` 与明确引用类型的标识符一起使用?
【发布时间】:2019-04-20 20:34:21
【问题描述】:

通常,typename 用于区分标识符可能引用类型或引用其他内容的情况:

template<class T>
void foo(typename T::type value) {
   // ...
}

当标识符已经是类型时,什么时候可以使用typename

1.如果已经有同名的类可以使用吗?

class MyClass{};

void foo(typename MyClass value) {}

2.它可以与声明为类型的模板参数一起使用吗?

template<class T>
void foo(typename T value) {}

3. 可以与明确类型的内部类一起使用吗?

class A {
   public:
    class B {};
};

// Compiles; no typename necessary
void foo(A::B value) {} 
// This compiles too on gcc and msvc
void bar(typename A::B value) {}

编译器解释

案例 1: MSVC 认为这没问题; gcc 和 clang 抛出错误

案例 2: MSVC 认为这没问题; gcc 和 clang 抛出错误

案例 3: A::B 无疑是一种类型,但 gcc 和 clang 现在允许使用 typename

【问题讨论】:

    标签: c++ syntax language-lawyer


    【解决方案1】:

    关键字 typename 仅允许 C++ syntax 引入 template type parameterbefore a qualified name,即包含 :: 令牌的内容。

    所以你的 #1 和 #2 格式不正确,因为 MyClassT 是不合格的名称,不包含任何 ::

    在限定名称之前,typename 标记是:

    C++17 [temp.res]/3,5,6:

    qualified-id 旨在引用不是当前实例化成员的类型并且其 nested-name-specifier 引用依赖类型时, 它应该以关键字typename 为前缀,形成一个typename-specifier。 ...

    class-or-decltype(子句 [class.derived])或 elaborated-type-specifier 中用作名称的限定名称隐含地假定为命名一个类型,不使用typename 关键字。在立即包含依赖于模板参数的 nested-name-specifiernested-name-specifier 中,identifier simple-template-id 被隐式假定为命名一个类型,而不使用 typename 关键字。 [注意: 这些构造的语法不允许使用 typename 关键字。 - 尾注]

    如果,对于给定的一组模板参数,一个模板的特化被实例化,它引用一个表示类型或类模板的 qualified-id,并且 qualified- id 指代未知专业化的成员,qualified-id 应以typename 为前缀,或者应在隐含命名类型的上下文中使用,如上所述.

    因此,您的 #3 格式正确,即使名称不依赖于模板参数,甚至不在模板声明中。

    注意 C++20 将添加 many more contexts,其中 typename 是可选的,即使有从属名称,因为可以从上下文中明确确定名称只能表示类型。

    【讨论】:

      【解决方案2】:

      来自cppreference

      用法:

      • 在模板声明中,typename 可以用作 class 的替代项来声明类型模板参数和模板模板参数(C++17 起)。
      • 在模板的声明或定义中,typename 可用于声明从属名称是一种类型。
      • 在类型要求的要求中(C++20 起)

      所以我会说你不能保证案例 1 和案例 2 会编译。因为它们不属于这三种用例中的任何一种。

      对于案例 3,让我们看看 cppreference 对此有何评论:

      关键字typename只能以这种方式使用在限定名称之前(例如T::x),但名称不必依赖。

      关键字 typename 只能在模板声明和定义中使用,并且只能在可以使用依赖名称的上下文中使用。这不包括显式特化声明和显式实例化声明。(C++11 前)

      关键字 typename 甚至可以在模板之外使用。 (C++11 起)

      因此,由于您的示例中没有模板,因此应保证案例 3 仅在 C++11 之后才有效

      确实有一个测试程序使用 g++ -std=c++11 编译成功,但在没有 -std=c++ 的情况下发出此警告11

      警告:'typename' 出现在模板之外 [-Wc++11-扩展]

      【讨论】:

      • 以“标准”的名义链接到 cppreference 充其量是不正确的。
      猜你喜欢
      • 2015-04-25
      • 1970-01-01
      • 2018-07-14
      • 2011-02-24
      • 1970-01-01
      • 1970-01-01
      • 2019-12-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多