通常,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
。
答案 0 :(得分:1)
用法:
- 在模板声明中,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 parameter或before a qualified name,即包含::
令牌的内容。
因此,您的#1和#2格式错误,因为MyClass
和T
是不合格的名称,不包含任何::
。
在使用合格名称之前,typename
令牌是:
class
, struct
, or union
keywords之前的语法不允许;在这些情况下,始终将合格名称视为类型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
是可选的,即使具有从属名称,因为可以从上下文中明确确定名称仅表示类型。