什么时候可以将`typename`与明确引用类型的标识符一起使用?

时间:2019-04-20 20:34:21

标签: c++ syntax language-lawyer

通常,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

2 个答案:

答案 0 :(得分:1)

来自cppreference

  

用法:

     
      
  • 在模板声明中,typename可以用作类的替代方法,以声明类型模板参数和模板模板参数(自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 编译了OK,但发出了此警告而没有 -std = c ++ 11

  

警告:“类型名”出现在模板之外         [-Wc ++ 11-扩展名]

答案 1 :(得分: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关键字。在一个嵌套名称说明符中,该嵌套名称说明符立即取决于模板参数,该 identifier 假定使用simple-template-id 命名类型,而无需使用typename关键字。 [注意:这些结构的语法不允许使用typename关键字。 -尾注]

     

如果对于给定的一组模板参数,实例化的模板专门化是指表示类型或类模板的 qualified-id ,而 qualified- id 指未知专业领域的成员, qualified-id 应该以{{1​​}}为前缀,或在其隐式地将类型命名为如上所述。

#3格式正确,即使名称不依赖模板参数,也不在模板声明中。

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