C++箴言:理解typename两个含义
2008-03-08 21:27:41 来源:WEB开发网核心提示:在下面的 template declarations(模板声明)中 class 和 typename 有什么不同? template class Widget; // uses "class" template class Widget; // uses "typename"
在下面的 template declarations(模板声明)中 class 和 typename 有什么不同?
template class Widget; // uses "class"
template class Widget; // uses "typename"
答案:没什么不同。在声明一个 template type parameter(模板类型参数)的时候,class 和 typename 意味着完全相同的东西。一些程序员更喜欢在所有的时间都用 class,因为它更轻易输入。其他人(包括我本人)更喜欢 typename,因为它暗示着这个参数不必要是一个 class type(类类型)。少数开发者在任何类型都被答应的时候使用 typename,而把 class 保留给仅接受 user-defined types(用户定义类型)的场合。但是从 C++ 的观点看,class 和 typename 在声明一个 template parameter(模板参数)时意味着完全相同的东西。
然而,C++ 并不总是把 class 和 typename 视为等同的东西。有时你必须使用 typename。为了理解这一点,我们不得不讨论你会在一个 template(模板)中涉及到的两种名字。
假设我们有一个函数的模板,它能取得一个 STL-compatible container(STL 兼容容器)中持有的能赋值给 ints 的对象。进一步假设这个函数只是简单地打印它的第二个元素的值。它是一个用糊涂的方法实现的糊涂的函数,而且就像我下面写的,它甚至不能编译,但是请将这些事先放在一边——有一种方法能发现我的愚蠢:
template // PRint 2nd element in
void print2nd(const C& container) // container;
{
// this is not valid C++!
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
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++ 解析器的人必须考虑所有可能的输入,甚至是愚蠢的。
在下面的 template declarations(模板声明)中 class 和 typename 有什么不同?
template class Widget; // uses "class"
template class Widget; // uses "typename"
答案:没什么不同。在声明一个 template type parameter(模板类型参数)的时候,class 和 typename 意味着完全相同的东西。一些程序员更喜欢在所有的时间都用 class,因为它更轻易输入。其他人(包括我本人)更喜欢 typename,因为它暗示着这个参数不必要是一个 class type(类类型)。少数开发者在任何类型都被答应的时候使用 typename,而把 class 保留给仅接受 user-defined types(用户定义类型)的场合。但是从 C++ 的观点看,class 和 typename 在声明一个 template parameter(模板参数)时意味着完全相同的东西。
然而,C++ 并不总是把 class 和 typename 视为等同的东西。有时你必须使用 typename。为了理解这一点,我们不得不讨论你会在一个 template(模板)中涉及到的两种名字。
假设我们有一个函数的模板,它能取得一个 STL-compatible container(STL 兼容容器)中持有的能赋值给 ints 的对象。进一步假设这个函数只是简单地打印它的第二个元素的值。
它是一个用糊涂的方法实现的糊涂的函数,而且就像我下面写的,它甚至不能编译,但是请将这些事先放在一边——有一种方法能发现我的愚蠢:
template // print 2nd element in
void print2nd(const C& container) // container;
{
// this is not valid C++!
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
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++ 解析器的人必须考虑所有可能的输入,甚至是愚蠢的。
在下面的 template declarations(模板声明)中 class 和 typename 有什么不同?
template class Widget; // uses "class"
template class Widget; // uses "typename"
答案:没什么不同。在声明一个 template type parameter(模板类型参数)的时候,class 和 typename 意味着完全相同的东西。一些程序员更喜欢在所有的时间都用 class,因为它更轻易输入。其他人(包括我本人)更喜欢 typename,因为它暗示着这个参数不必要是一个 class type(类类型)。少数开发者在任何类型都被答应的时候使用 typename,而把 class 保留给仅接受 user-defined types(用户定义类型)的场合。但是从 C++ 的观点看,class 和 typename 在声明一个 template parameter(模板参数)时意味着完全相同的东西。
然而,C++ 并不总是把 class 和 typename 视为等同的东西。有时你必须使用 typename。为了理解这一点,我们不得不讨论你会在一个 template(模板)中涉及到的两种名字。
假设我们有一个函数的模板,它能取得一个 STL-compatible container(STL 兼容容器)中持有的能赋值给 ints 的对象。进一步假设这个函数只是简单地打印它的第二个元素的值。它是一个用糊涂的方法实现的糊涂的函数,而且就像我下面写的,它甚至不能编译,但是请将这些事先放在一边——有一种方法能发现我的愚蠢:
template // print 2nd element in
void print2nd(const C& container) // container;
{
// this is not valid C++!
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
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++ 解析器的人必须考虑所有可能的输入,甚至是愚蠢的。
更多精彩
赞助商链接