Linux | c&cpp | Email | github | QQ群:425043908 关注本站

itarticle.cc

您现在的位置是:网站首页 -> 代码相关 文章内容

C++模板类中的typename关键字-itarticl.cc-IT技术类文章记录&分享

发布时间: 7年前代码相关 116人已围观返回

模板(template)中typename的使用方法

声明template参数时, 前缀关键字class和typename可以互换;

使用关键字typename标识嵌套从属类型名称, 但不需在基类列表和成员初始化列表内使用.

从属名称(dependent names): 模板(template)内出现的名称, 相依于某个模板(template)参数, 如T t;

嵌套从属名称(nested dependent names):从属名称在class内呈嵌套装, 如T::const_iterator ci;

非从属名称(non-dependent names): 不依赖任何template参数的名称, 如int value;

如果不特定指出typename, 嵌套从属名称, 有可能产生解析(parse)歧义.


1.任何时候在模板(template)中指涉一个嵌套从属类型名称, 需要在前一个位置, 添加关键字typename;

否则报错(GCC): error: need 'typename' before 'T::xxx' because 'T' is a dependent scope

代码:

#include <iostream>

#include <string>

#include <vector>


using namespace std;


template<typename T>

void print2nd(const T& container) {

typename T::const_iterator iter(container.begin()); //未加typename, 报错

++iter;

int value = *iter;

std::cout << value;

}


int main () {

vector<int> vi = {1,2,3,4,5};

print2nd(vi);


return 0;

}

输出:

[plain] view plain copy


2.例外:嵌套从属类型名称, 如果是基类列表(base class list)和成员初值列(member initialization list)中,不使用typename;

代码:

#include <iostream>

#include <vector>


using namespace std;


struct Number {

Number(int x) {

std::cout << "Number = " << x << std::endl;

}

};


template<typename T>

struct Base{

typedef Number Nested;

};


template<typename T>

class Derived: public Base<T>::Nested { //不用typename

public:

explicit Derived(int x) : Base<T>::Nested(x) { //不用typename

typename Base<T>::Nested temp(7); //必须使用

}

};


int main () {

Derived<int> d(5);


return 0;

}

输出:

[plain] view plain copy

Number = 5

Number = 7


3.当使用特性类(traits class)时, 必须使用typename, 如

代码:

#include <array>

#include <iostream>


using namespace std;


template<typename T>

void workWithIter(T iter) {

typedef typename std::iterator_traits<T>::value_type value_type; //使用typename

value_type temp(*iter);

std::cout << "temp = " << temp << std::endl;


}


int main () {

std::array<int, 5> ai = {1,2,3,4,5};

std::array<int, 5>::iterator aiIter = ai.begin();

workWithIter(aiIter);

return 0;

}

输出:

[plain] view plain copy

temp = 1


4. 模板中标明“内嵌依赖类型名”

这里有三个词,内嵌、依赖、类型名。那么什么是“内嵌依赖类型名(nested dependent type name)”?

请看SGI STL里的一个例子, 只是STL中count范型算法的实现:

template <class _InputIter, class _Tp>

typename iterator_traits<_InputIter>::difference_type

count(_InputIter __first, _InputIter __last, const _Tp& __value) {

__STL_REQUIRES(_InputIter, _InputIterator);

__STL_REQUIRES(typename iterator_traits<_InputIter>::value_type,

_EqualityComparable);

__STL_REQUIRES(_Tp, _EqualityComparable);

typename iterator_traits<_InputIter>::difference_type __n = 0;

for ( ; __first != __last; ++__first)

if (*__first == __value)

++__n;

return __n;

}


//这里有三个地方用到了typename:返回值、参数、变量定义。分别是:

typename iterator_traits<_InputIter>::difference_type

typename iterator_traits<_InputIter>::value_type

typename iterator_traits<_InputIter>::difference_type __n = 0;

//difference_type, value_type就是依赖于_InputIter(模板类型参数)的类型名。源码如下:

template <class _Iterator>

struct iterator_traits {

typedef typename _Iterator::iterator_category iterator_category;

typedef typename _Iterator::value_type value_type;

typedef typename _Iterator::difference_type difference_type;

typedef typename _Iterator::pointer pointer;

typedef typename _Iterator::reference reference;

};

内嵌是指定义在类名的定义中的。以上difference_type和value_type都是定义在iterator_traits中的。

依赖是指依赖于一个模板参数。typename iterator_traits<_InputIter>::difference_type中difference_type依赖于模板参数_InputIter。

类型名是指这里最终要指出的是个类型名,而不是变量。例如iterator_traits<_InputIter>::difference_type完全有可能是类iterator_traits<_InputIter>类里的一个static对

象。而且当我们这样写的时候,C++默认就是解释为一个变量的。所以,为了和变量区分,必须使用typename告诉编译器。

发布时间: 7年前代码相关116人已围观返回回到顶端

很赞哦! (1)

文章评论

  • 请先说点什么
    热门评论
    115人参与,0条评论

站点信息

  • 建站时间:2016-04-01
  • 文章统计:728条
  • 文章评论:82条
  • QQ群二维码:扫描二维码,互相交流