设为首页 加入收藏

TOP

c++ typename 关键字扫盲(一)
2013-04-10 11:40:16 来源: 作者: 【 】 浏览:409
Tags:  typename  关键字 扫盲

  [cpp] view plaincopy

  typedef _CharT                  char_type;

  typedef _Traits                     traits_type;

  typedef typename traits_type::int_type      int_type;

  typedef typename traits_type::pos_type      pos_type;

  typedef typename traits_type::off_type      off_type;

  问题:在下面的 template declarations(模板声明)中 class 和 typename 有什么不同?

  template<class T> class Widget; // uses "class"

  template<typename T> class Widget; // uses "typename"

  答案:没什么不同。在声明一个 template type parameter(模板类型参数)的时候,class 和 typename 意味着完全相同的东西。一些程序员更喜欢在所有的时间都用 class,因为它更容易输入。其他人(包括我本人)更喜欢 typename,因为它暗示着这个参数不必要是一个 class type(类类型)。少数开发者在任何类型都被允许的时候使用 typename,而把 class 保留给仅接受 user-defined types(用户定义类型)的场合。但是从 C++(www.cppentry.com) 的观点看,class 和 typename 在声明一个 template parameter(模板参数)时意味着完全相同的东西。

  然而,C++(www.cppentry.com) 并不总是把 class 和 typename 视为等同的东西。有时你必须使用 typename.为了理解这一点,我们不得不讨论你会在一个 template(模板)中涉及到的两种名字。

  假设我们有一个函数的模板,它能取得一个 STL-compatible container(STL 兼容容器)中持有的能赋值给 ints 的对象。进一步假设这个函数只是简单地打印它的第二个元素的值。它是一个用糊涂的方法实现的糊涂的函数,而且就像我下面写的,它甚至不能编译,但是请将这 些事先放在一边--有一种方法能发现我的愚蠢:

  template<typename C> // print 2nd element in

  void print2nd(const C& container) // container;

  {

  // this is not valid C++(www.cppentry.com)!

  if (container.size() >= 2) {

  C::const_iterator iter(container.begin()); // get iterator to 1st element

  ++iter; // move iter to 2nd element

  int value = *iter; // copy that element to an int

  std::cout 《 value; // print the int

  }

  }

  我突出了这个函数中的两个 local variables(局部变量),iter 和 value.iter 的类型是 C::const_iterator,一个依赖于 template parameter(模板参数)C 的类型。一个 template(模板)中的依赖于一个 template parameter(模板参数)的名字被称为 dependent names(依赖名字)。当一个 dependent names(依赖名字)嵌套在一个 class(类)的内部时,我称它为 nested dependent name(嵌套依赖名字)。C::const_iterator 是一个 nested dependent name(嵌套依赖名字)。实际上,它是一个 nested dependent type name(嵌套依赖类型名),也就是说,一个涉及到一个 type(类型)的 nested dependent name(嵌套依赖名字)。

  print2nd 中的另一个 local variable(局部变量)value 具有 int 类型。int 是一个不依赖于任何 template parameter(模板参数)的名字。这样的名字以 non-dependent names(非依赖名字)闻名。(我想不通为什么他们不称它为 independent names(无依赖名字)。如果,像我一样,你发现术语 "non-dependent" 是一个令人厌恶的东西,你就和我产生了共鸣,但是 "non-dependent" 就是这类名字的术语,所以,像我一样,转转眼睛放弃你的自我主张。)

  nested dependent name(嵌套依赖名字)会导致解析困难。例如,假设我们更加愚蠢地以这种方法开始 print2nd:

  template<typename C>

  void print2nd(const C& container)

  {

  C::const_iterator * x;

  …

  }

  这看上去好像是我们将 x 声明为一个指向 C::const_iterator 的 local variable(局部变量)。但是它看上去如此仅仅是因为我们知道 C::const_iterator 是一个 type(类型)。但是如果 C::const_iterator 不是一个 type(类型)呢?如果 C 有一个 static data member(静态数据成员)碰巧就叫做 const_iterator 呢?再如果 x 碰巧是一个 global variable(全局变量)的名字呢?在这种情况下,上面的代码就不是声明一个 local variable(局部变量),而是成为 C::const_iterator 乘以 x!当然,这听起来有些愚蠢,但它是可能的,而编写 C++(www.cppentry.com) 解析器的人必须考虑所有可能的输入,甚至是愚蠢的。

  直到 C 成为已知之前,没有任何办法知道 C::const_iterator 到底是不是一个 type(类型),而当 template(模板)print2nd 被解析的时候,C 还不是已知的。C++(www.cppentry.com) 有一条规则解决这个歧义:如果解析器在一个 template(模板)中遇到一个 nested dependent name(嵌套依赖名字),它假定那个名字不是一个 type(类型),除非你用其它方式告诉它。缺省情况下,nested dependent name(嵌套依赖名字)不是 types(类型)。(对于这条规则有一个例外,我待会儿告诉你。)

  记住这个,再看看 print2nd 的开头:

  template<typename C>

  void print2nd(const C& container)

  {

  if (container.size() >= 2) {

  C::const_iterator iter(container.begin()); // this name is assumed to

  … // not be a type

  这为什么不是合法的 C++(www.cppentry.com) 现在应该很清楚了。iter 的 declaration(声明)仅仅在 C::const_iterator 是一个 type(类型)时才有意义,但是我们没有告诉 C++(www.cppentry.com) 它是,而 C++(www.cppentry.com) 就假定它不是。要想转变这个形势,我们必须告诉 C++(www.cppentry.com) C::const_iterator 是一个 type(类型)。我们将 typename 放在紧挨着它的前面来做到这一点:

  template<typename C> // this is valid C++(www.cppentry.com)

  void print2nd(const C& container)

  {

  if (container.size() >= 2) {

  typename C::const_iterator iter(container.begin());

  …

  }

  }

   

首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇c++实现欧拉回路问题 下一篇如何对C++虚基类构造函数

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: