C++ typedef和typename关键字


前序

在《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);
    // .....
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值