当前位置: 首页 > news >正文

typename 的用法

Usage

typename 主要有两个作用,让我们先来看看标准手册对该关键字的说明。

  • In the template parameter list of a template declaration, typename can be used as an alternative to class to declare type template parameters.
    • 在模板声明的模板参数列表中,typename 可以用来替换 class 声明模板参数类型
  • Inside a declaration or a definition of a template, typename can be used to declare that a dependent qualified name is a type.
    • 在模板的声明或定义中,typename 可以用来声明从属名称是一种类型

声明模板参数类型

以下 tempalate 声明式中,class 和 typename 用什么不同?

template <class T>
class Qgw;

template <typename T>
class Qgw;

答案:完全一样。标准中说 typename 可以用来替换 class 声明模板参数类型,并没有说在此时有什么不同。

声明嵌套从属名称

在了解这个作用前,我们需要先学习两种名称,从属名称(dependent names)和嵌套从属名称(nested dependent name)。

让我们来看这样一段代码,代码本身并没有实际意义。

// C 接收一个 STL 容器类型
// 这份代码并不正确
template <class C>
void Test(C& container)
{
    C w;
    C::iterator iter(container.begin());
}

在上述代码中有两个局部变量 w 和 iter。w 的类型是 C,实际是什么取决于 template 参数 C。template 内出现的名称如果依赖于某个 template 参数称之从属名称。如果从属名称在 class 内呈嵌套状,就称为嵌套从属名称,像 iter 的类型为 C::iterator,就是一个嵌套从属名称。

嵌套从属名称有可能导致解析困难,先来看个比较极端的例子:

template <class C>
void Test(C& container)
{
    C::iterator* x;
    ...
}

上述代码我们声明了一个局部变量 x,它是个指针,指向一个 C::iterator。但它之所以被这么认为,是因为我们已经知道 C::iterator 是个类型。如果 C::iterator 不是个类型呢?如果 C 有个 static 成员变量而又刚好叫 iterator,或者 x 是个全局变量呢?那样的话上述代码不再是声明一个局部变量,而是一个相乘动作。

在我们知道 C 是什么之前,没有任何办法可以知道 C::iterator 是否是一个类型。C++ 有个规则可以解析这一歧义状态:如果解析器在 template 中遇到一个嵌套从属名称,它便假设这名称不是一个类型,除非你明确指出它是一个类型。所以缺省情况下嵌套从属名称不是类型,有两个例外会在下面指出。

我们可以用 typename 来明确指出嵌套从属名称是一个类型,标准中写到 typename 可以用来声明从属名称是一种类型。于是我们可以这样修改代码:

template <class C>
void Test(C& container)
{
    C w;
    typename C::iterator iter(container.begin());
    typename C::iterator* x;
}

一个简单的规则:任何时候当你想在 template 中指涉一个嵌套从属名称,就必须在它的前一个位置放上关键字 typename。

typename 只能被用来验明嵌套从属名称,其他名称不该有它存在。

template <class C>
void Test(const C& container, 			// 不允许使用 typename,vs 下没报错,g++ 报错了
          typename C::iterator iter);	// 一定要使用 typename

例外

typename 不可以出现在 base classes list 内嵌套从属名称之前,也不可以在 member initialization list(成员初始化列表)中作为 base class 修饰符。例如:

temalate <class T>
class Derived : public Base<T>::Nested	// base classes list 中不允许 typename
{
public:
    Derived (int x)
    	: Base<T>::Nested(x)			// mem. init. list 中不允许 typename
    {
        typename Base<T>::Nested temp;	// 既不在 base classes list 也不在 mem. init. list 需要加 typename
    }
}

相关文章:

  • java题2
  • 【Python深度学习】深度学习框架搭建模版
  • 双绞线连接网卡和集线器时的制作步骤
  • vue实战-mockjs模拟数据
  • 深度学习优化算法之动量法[公式推导](MXNet)
  • tomcat面试和Spring的面试题
  • 网课查题公众号接口
  • 基于Hive的搜狗搜索日志与结果Python可视化设计
  • vue+echarts项目四:地区销量趋势(堆叠折线图)
  • SpringSecurity实战-第6-8章
  • 前端 基础知识
  • 【极客时间2】左耳听风
  • 六级高频词汇——Group07
  • C++类和对象详解(中篇)
  • java五位随机验证码的实现。要求前四位是随机大小写的字母,最后一位是数字的组合。例如qWrY4
  • co模块的前端实现
  • gf框架之分页模块(五) - 自定义分页
  • gitlab-ci配置详解(一)
  • iOS筛选菜单、分段选择器、导航栏、悬浮窗、转场动画、启动视频等源码
  • PHP 的 SAPI 是个什么东西
  • React-redux的原理以及使用
  • Vim 折腾记
  • vue2.0项目引入element-ui
  • Webpack入门之遇到的那些坑,系列示例Demo
  • 给Prometheus造假数据的方法
  • 基于Dubbo+ZooKeeper的分布式服务的实现
  • 可能是历史上最全的CC0版权可以免费商用的图片网站
  • 山寨一个 Promise
  • 物联网链路协议
  • python最赚钱的4个方向,你最心动的是哪个?
  • raise 与 raise ... from 的区别
  • RDS-Mysql 物理备份恢复到本地数据库上
  • ​【已解决】npm install​卡主不动的情况
  • ​Linux·i2c驱动架构​
  • (2)(2.10) LTM telemetry
  • (2)STL算法之元素计数
  • (ISPRS,2023)深度语义-视觉对齐用于zero-shot遥感图像场景分类
  • (六)vue-router+UI组件库
  • (十六)Flask之蓝图
  • (一)基于IDEA的JAVA基础1
  • (转)【Hibernate总结系列】使用举例
  • ***检测工具之RKHunter AIDE
  • .h头文件 .lib动态链接库文件 .dll 动态链接库
  • .NET 6 在已知拓扑路径的情况下使用 Dijkstra,A*算法搜索最短路径
  • .net core 客户端缓存、服务器端响应缓存、服务器内存缓存
  • .net core控制台应用程序初识
  • .NET Reactor简单使用教程
  • .NET 表达式计算:Expression Evaluator
  • .net 无限分类
  • .Net 转战 Android 4.4 日常笔记(4)--按钮事件和国际化
  • .NET6 开发一个检查某些状态持续多长时间的类
  • .NET基础篇——反射的奥妙
  • .pyc文件还原.py文件_Python什么情况下会生成pyc文件?
  • /bin/bash^M: bad interpreter: No such file or directory
  • /etc/apt/sources.list 和 /etc/apt/sources.list.d