C++ typedef和typename关键字

来源:互联网 发布:恶搞锁屏软件 编辑:程序博客网 时间:2024/06/07 03:35

前序

在《STL源码解析》一书中看到了这样一段代码

template <class ForwardIterator, class Size, class T, class T1>inline ForwardIterator __uninitialized_fill_n(ForwardIterator first, Size n, const T& x, T1*){    typedef typename __type_traits<T1>::is_POD_type is_POD;    return __uninitialized_fill_n_aux(first, n, x, is_POD());}

在代码的第三行中出现的

typedef typename __type_traits<T1>::is_POD_type is_POD;

可能会让初学者感到无法理解,难以接受。这里的typedef 还好理解,但是typename又是啥鬼?:tw-1f62c:
在《C++Primer 5th》P593页和《Effective C++》第42条都讲解了这部分内容,我也总结了下给大家,方便大家解惑。

类型别名typedef

类型说明的格式为:
typedef 类型 定义名;

它用来对一个数据类型取一个新名字。其中定义名表示这个类型的新名字。

例如:

typedef int type_int;   // 这里的type_int就是整形int的另一个名字,接下来可以用type_int代替int

类型解释typename

定义

在维基百科中这样解释:
当用于泛型编程时是另一术语”class”的同义词。这个关键字用于指出模板声明(或定义)中的非独立名称(dependent names)是类型名,而非变量名。

例如声明一个人的模板类

template <typename T>class Person{    // .... };// 或者template <class T>class Person{};

使用类的类型成员

通常我们使用作用域运算符(::)来访问static成员和类型成员。在普通(非模板)代码中,编译器掌握类的定义。因此,他知道通过作用域运算符访问的名字是类型还是static成员。例如:string::size_type,编译器有string的定义,从而知道size_type是一个类型。

但是如果是模板类就变得很困难了。

例如:

template <typename C>void print2nd(const C& contrainer){    // ...    C::const_iterator* x;           // 申明x为一个指针,指向C::const_iterator    // ...};

这段代码看起来好像是对,但是它确实是错的,回到之前我们之所以认为它对,是因为我们“知道”C::const_iterator是一个类型,但是如果C::const_iterator不是一个类型呢,如果它是一个static成员变量呢?又或者是一个全局变量呢?那么上述的用法就变为相乘了。

因此有必要说明C::const_iterator是一个类型。只要在紧邻它之前放置关键字typename即可
例如

template <typename C>void print2nd(const C& contrainer){    // ...    typename C::const_iterator* x;          // 申明x为一个指针,指向C::const_iterator    // ...};

这个规则很简单:在任何时候当你想在template中涉及一个嵌套从属类型名称,就必须在紧临它的前一个位置放置上关键字typename(也有例外)


“typename作为嵌套从属类型名称的前缀词”的例外
template 不可以出现在base classes list内的嵌套从属类型名称之前,也不可以出现在memeber initialization list(成员初始列表)中作为base class 修饰词, 例如:

template <typename T>class Derived : public Base<T>::Nested  //  Base classes list,不允许出现"typename"{public:    explicit Derived(int x) :     Base<T>::Nested(x)              // 成员初始化列表,不允许出现"typename"    {               typename Base<T>::Nested temp;              // 嵌套从属类型名称    }};

typedef和typename共用

回到最初的问题,这里我们用另外一个例子代替

template <typename IterT>void workWithIterator(IterT iter){    typename std::iterator_traits<IterT>::value_type temp(*iter);}

看起来任然可能有点蒙, 所以先讲下traits

traits(特性萃取机)

在我们日常中,常用到的迭代器相应型别有5中:value_type, difference_type, pointer, reference, iterator catagoly。而“特性萃取机”traits会忠实的原汁原味的榨取出来:

template <class I>struct iterator_traits{    typedef typename I::iterator_category     iterator_category;    typedef typename I::value_type              value_type;    typedef typename I::difference_type         difference_type;    typedef typename I::pointer                      pointer;    typedef typename I::reference                 reference;}

std::iterator_traits<IterT>::value_type说的就是”类型为IterT之对象所指之物的类型”
如果你的IterT为vector<int>::iterator,temp的类型就是int,
如果你的IterT为list<sting>::iterator,temp的类型就是string

说完上面哪行代码就解释的通了
std::iterator_traits<IterT>::value_type是一个嵌套从属类型名(value_type被嵌套与iterator_traits<IterT>之内而IterT是一个template参数),所以必须在它之前放置typename

而为了简化书写,加上typedef,完美:tw-1f604:
最终代码

template <typename IterT>void workWithIterator(IterT iter){    typedef typename std::iterator_traits<IterT>::value_type value_type;    value_type temp(*iter);    // .....}
1 0
原创粉丝点击