Typename和Class在声明模板时的区别

来源:互联网 发布:windows to go下载 编辑:程序博客网 时间:2024/05/22 05:16

转载:http://wenku.baidu.com/view/ced26508b52acfc789ebc91b.html

Typename和Class在声明模板时的区别     

声明template参数时,前缀关键词class和typename可互换。也就是说以下两个没有区别:

(1)template<class T>class Widget;

(2)template<typename>class Widget。 

然而C++并不总是把class和typename视为等价。有时一定得使用typename。

 这种时机就是:任何时候当想要在template中指涉一个嵌套从属类型名称,就必须在紧邻它的前一个位置放上关键字typename,只有如下一个例外:不得在base class list(基类列)或member initialization list(成员初值列)内以它作为base class修饰符。

其中:template内出现的名称如果相依于某个template参数,称之为从属名称。如果从属名称在class内呈嵌套状,我们称它为嵌套从属名称。C::const_iterator(看下面例子)就是这样的一个名称。实际上它还是个嵌套从属类型名称,也就是个嵌套从属名称并且指涉某类型。看下面例子:

template <typename C> 

void print2nd(const C& container)

{  

    if(container.size()>=2) 

    {   

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

        ++iter;  

        int value = *iter;  

        cout<<value<<endl; 

   }

嵌套从属名称有可能引起解析困难。如下面的例子(将上面的改一下):

template <typename C> 

void print2nd(const C& container)

{   C::const_iterator* x;  ... } 

按照正常的理解我们应该是声明了一个x的局部变量,但是前提是我们知道C::const_iterator是个类型,但是万一不是呢,比如C是个类并且它有一个const_iterator的静态成员变量呢而且x又是一个全局变量,那么上面的就是一个相乘的动作,即C::const_iterator乘以x。引起歧义。 

在我们知道C是什么之前,没有任何办法可以知道C::const_iterator是否是一个类型。而当编译器开始解析template print2nd时,尚未知C是什么东西。C++有个规则可以解析此一歧义状态:如果解析器在template中遭遇一个嵌套从属名称,它便假设这名称不是一个类型,除非你告诉它是。所以缺省情况下嵌套从属名称不是类型。此规则有个例外,稍后会谈到。我们告诉它是只需在C::const_iterator前加上关键字typename即可。  注意typename只被用来验明嵌套从属类型名称;其他名称不该有它存在。如下面的例子:

template<typename C> 

void f(const C& container,typename C::iterator iter)。

参数中第一个不是嵌套从属类型名称,所以不需要关键字typename,而第二个需要。 

 

“typename必须作为嵌套从属类型名称的前缀词”这一规则的例外是,typename不可以出现在base classes list内的嵌套从属类型名称之前,也不可在member initalization list(成员初始列)中作为base class修饰符。例如: template<typename T> 

class Derived:public Base<T>::Nested      //base list中不允许"typename"

{

public:  

    explicit Derived(int x)    :Base<T>::Nested(x)                //mem init list中不允许有"typename" 

    {   

         typename Base<T>::Nested temp;     //这个一定要有"typename" 

    }

 } 

  最后声明一点:以上讲的在VC++ 6.0下不适用,也就是说在VC下不用typename修饰嵌套从属类型,编译器也不会抱怨,但是在gcc内核下就会发生抱怨。    参考文献:《Effective C++》

 

 

转载:http://blogs.msdn.com/b/slippman/archive/2004/08/11/212768.aspx

 

Why C++ Supports both Class and Typename for Type Parameters

 

Recently, someone asked me why we support both class and typename within C++ to indicate a type parameter since the keywords do not hold any platform significance – for example, class is not meant to suggest a native type nor is typename meant to suggest a CLI type. Rather, both equivalently indicate that the name following represents a parameterized type placeholder that will be replaced by a user-specfied actual type.

The reason for the two keywords is historical. In the original template specification, Stroustrup reused the existing class keyword to specify a type parameter rather than introduce a new keyword that might of course break existing programs. It wasn't that a new keyword wasn't considered -- just that it wasn't considered necessary given its potential disruption. And up until the ISO-C++ standard, this was the only way to declare a type parameter.

Reuses of existing keywords seems to always sow confusion. What we found is that beginners were whether the use of the class constrained or limited the type arguments a user could specify to be class types rather than, say, a built-in or pointer type. So, there was some feeling that not having introduced a new keyword was a mistake.

During standardization, certain constructs were discovered within a template definition that resolved to expressions although they were meant to indicate declarations. For example,

template <class T>

class Demonstration {

public:

void method() {

    T::A *aObj; // oops …

     // …

};

While the statement containing aObj is intended by the programmer to be interpreted as the declaration of a pointer to a nested type A within the type parameter T, the language grammar interprets it as an arithmetic expression multiplying the static member A of type T with aObj and throwing away the result. Isn't that annoying! (This sort of dilemna is not possible within generics – there is no way to safely verify that any T contains an A so that the runtime can safely construct an instance of the generic type.)

The committee decided that a new keyword was just the ticket to get the compiler off its unfortunate obsession with expressions. The new keyword was the self-describing typename. When applied to a statement, such as,

typename T::A* a6; // declare pointer to T’s A

it instructs the compiler to treat the subsequent statement as a declaration. Since the keyword was on the payroll, heck, why not fix the confusion caused by the original decision to reuse the class keyword. Of course, given the extensive body of existing code and books and articles and talks and postings using the class keyword, they chose to also retain support for that use of the keyword as well. So that's why you have both.

 

原创粉丝点击