1ms Faster
Home
  • Program

    • Lean in C++
  • Perfromance Engineering

    • [>>>>>]
  • Reading Note

    • [>>>>>]
  • ComputeArch

    • [_]
  • Compiler

    • [_]
  • System

    • [_]
Authoring
  • Categories
  • Tags
GitHub (opens new window)

Quincy Jet

We are.
Home
  • Program

    • Lean in C++
  • Perfromance Engineering

    • [>>>>>]
  • Reading Note

    • [>>>>>]
  • ComputeArch

    • [_]
  • Compiler

    • [_]
  • System

    • [_]
Authoring
  • Categories
  • Tags
GitHub (opens new window)
  • Lean in c++

    • Lean in C++
    • Phase_0:Glimpse

      • C++ Glimpse
      • type cast
      • typedef
      • class vs. typename
        • 1. 共同点
        • 2. typename 独有的功能
        • 3. class 独有的功能
      • const
      • extern
      • pointer
      • static
      • volatile
      • inline
      • assert
      • void
      • __global__
  • Performance Engineering

  • Misc

  • Reading Notes

  • Wiki
  • Lean in c++
  • Phase_0:Glimpse
Quincy Jet
2021-08-05
Content

class vs. typename

在class template/function template 的声明中, 既可以使用class也可以使用typename来对类型T进行表示, 所以他们有什么区别呢?

# 1. 共同点

在定义类模板或者函数模板时,typename 和 class 关键字都可以用于指定模板参数中的类型。也就是说,以下两种用法是完全等价的。这在大多数文章中都有提到。

template<typename T> /* class or function declaration */;
template<class T>  /* class or function declaration */;
1
2

Stan Lippman曾在其博客中表示,最早 Stroustrup 使用 class 来声明模板参数列表中的类型是为了避免增加不必要的关键字;后来标准委员会认为这样混用可能造成概念上的混淆才加上了 typename 关键字。

# 2. typename 独有的功能

由于 C++ 允许在类内定义类型别名,且其使用方法与通过类型名访问类成员的方法相同。故而,在类定义不可知的时候,编译器无法知晓类似 Type::foo 的写法具体指的是一个类型还是类内成员。这种情况下变量的类型发生了嵌套依赖类型(nested depended name)

在下面的两段代码中,类模板 Bar 的原意是使用类 Foo 实例化,而后引用其中的 bar_type 定义名为 bar 的类内成员。然而,就 T::bar_type 而言,编译器在编译期无法确定它究竟是不是一个类型。此时就需要 typename 关键字来辅助编译器的判断。typename 的作用就是告诉 c++ 编译器,typename 后面的字符串为一个类型名称,而不是成员函数或者成员变量,这个时候如果前面没有 typename,编译器没有任何办法知道 T::LengthType 是一个类型还是一个成员名称(静态数据成员或者静态函数),所以编译不能够通过。

EXP 1:

class Foo {
 public:
 typedef int bar_type;
};
 
template<typename T>
class Bar {
 T::bar_type bar; // Wrong !
 typename T::bar_type bar; // Right !
}; 
1
2
3
4
5
6
7
8
9
10

EXP 2:

class MyArray { 
    public:
    typedef int LengthType;
    ...
}

template<class T>
void MyMethod( T myarr ) { 
    typedef typename T::LengthType LengthType; 
    LengthType length = myarr.GetLength; 
}
1
2
3
4
5
6
7
8
9
10
11

这是常规的情形, <u>要注意的是,对于在编译期能够判断类型的场景,例如在上面例子中直接使用 Foo::bar_type 时,使用冗余的 typename 却会报错。</u>

# 3. class 独有的功能

class 关键字最众所周知的功能是声明或定义一个类。这当然是其相对 typename 的一个独有功能。为了完整性,这里也列出。除此之外,在模板的使用中,class 关键字也有其特有的功能。而这是绝大多数文章不会提及的。

C++ 的标准模板库中有名为 std::stack 的容器适配器,它能适配许多容器作为底层,实现栈的功能。其声明为

template <typename T, typename Containter = std::deque<T> >
class stack;
1
2

因此,在使用中,我们可以使用 std::stack<int> 来声明一个以 std::deque<int> 保存整型变量的栈;也可以使用 std::stack<int, std::vector<int> > 来声明一个以 std::vector<int> 保存整型变量的栈。

是否有可能以类似 Stack<int, std::vector> 的形式,来达到同样的目的?

所以我们需要有类似这样的声明:

template <typename T,
  template <typename E, typename = std::allocater<E> > class Container = std::deque>
class Stack;
1
2
3

由于 Container 必须是一个容器类模板,所以,如果不适用具体的模板参数实例化,就必须将其声明为一个类模板。故此,Container 之前需要保留标准库中容器类模板的模板参数。注意此处使用了标准库提供的内存分配器。

此处 class 特有的功能,体现在 class Container 之处。此处虽然是在声明 Stack 这个类模板,但是这里的 class 不能替换为 typename;否则编译器会报错。

不过,在 C++17标准中,这样的情况也允许使用 typename 了。参见此处 (opens new window)。

#C++
Last updated: 2023/03/11, 03:13:10
typedef
const

← typedef const→

Copyright © 2017-2023 Quincy Jet | MIT License
  • Auto
  • Light
  • Dark
  • Read