typename、typedef、using对比

news2024/11/15 19:36:05

在c++的标准库中,因为类继承关系比较复杂和模板使用比较多的原因,源代码中充斥着typename、typedef和using这三个关键字

一、typename关键字

1.1、typename的第一个作用是用作模板里面,来声明某种类型

template<typename _Tp, typename _Alloc>
    struct _Vector_base;

最开始的时候声明模板形参,也会使用class,但我们都知道class总要是用来指定一个类名,据说是为了避免混淆,所以后来增加了typename这个关键字,它告诉编译器,跟在它后面的字符串是一个不确定的类型,而不是变量或者其他什么东西。

1.2、typename在stl中还有另外一种作用

例1

//test.cpp
#include <ext/alloc_traits.h>
using namespace std;

template<typename _Tp, typename _Alloc>
class AA
{
typedef  typename __gnu_cxx::__alloc_traits<_Alloc>::template rebind<_Tp>::other _Tp_alloc_type;
};
这里顺便说一下rebind前面为啥要放一个template,它是为了告诉编译器后面的<>是用于指定模板参数,而进行比较。

这个时候我们使用g++ -c test.cpp -o test.o是可以编译通过的,但如果我们去掉第三个typename看,会发生什么呢?

再次编译,报错如下:

test.cpp:8:10: 错误:‘typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<_Tp>::other’之前需要‘typename’,因为‘typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<_Tp>’是一个有依赖的作用域
 typedef  __gnu_cxx::__alloc_traits<_Alloc>::template rebind<_Tp>::other _Tp_alloc_type;

编译器直接指明了需要一个typename,实际上typename在这里也是指定它后面的字符串为类型,这是因为对于形如AA::BB这样的形式,它有可能是一个类型,也有可能是类的静态成员,这个时候加上typename就是为了告诉编译器,它后面的一大串字符串都是一个类型。

template<typename T>
void print2nd(const T& container)
{
    typename T::const_iterator * x; //①
    ...
}

如果不加typename此时的编译器会纠结:const_iterator是一个什么东西?const_iterator是模板参数C内的一个static变量?x是一个全局变量?再或者:const_iterator是模板参数C内部的一个typedef。所以此时我们应该告诉编译器const_iterator是模板参数C里面的一个类型。即在C的前面加上typename就可以了

事实上类型T::const_iterator依赖于模板参数T, 模板中依赖于模板参数的名称称为从属名称(dependent name), 当一个从属名称嵌套在一个类里面时,称为嵌套从属名称(nested dependent name)。 其实T::const_iterator还是一个嵌套从属类型名称(nested dependent type name)。

嵌套从属名称是需要用typename声明的,其他的名称是不可以用typename声明的。

例2

template<typename T>
class myFoo
{
public:
    using size_type = std::size_t;

public:
    size_type size() const;
private:
    size_type mSize = 5;
};
template<typename T>
myFoo<T>::size_type myFoo<T>::size() const
{
    return mSize;
}

这种写法仍然不对,也会被编译器无情的拒绝。

因为,对于模板类,myFoo::size_type 这样的写法,会被认为是引用一个名为size_type的成员变量,而这里的size_type只是size_t的别名而已,是个类型名,而不是成员变量。

答案最终揭晓,正确的写法是,保证对size_type的引用是类型名的引用,其实解决方法并不止一种:

  • 其一:使用typename关键字,具体代码如下:
template<typename T>
typename myFoo<T>::size_type myFoo<T>::size() const
{
    return mSize;
}
  • 其二:使用auto和decltype关键字,具体代码如下(包含模板类的声明部分):
template<typename T>
class myFoo
{
public:
    using size_type = std::size_t;

public:
    auto size() const -> decltype(myFoo<T>::mSize);
private:
    size_type mSize = 5;
};

/** size成员函数实现 */
template<typename T>
auto myFoo<T>::size() const -> decltype(myFoo<T>::mSize)
{
    return mSize;
}
二、typedef关键字

typedef实际上就是给类型取了一个别名

三、using关键字

case1、 命名空间的使用

case2、在子类中引用基类的成员(私有保护或者函数隐藏的情况)

class T5Base {
public:
    T5Base() :value(55) {}
    virtual ~T5Base() {}
    void test1() { cout << "T5Base test1..." << endl; }
protected:
    int value;
};
 
class T5Derived : private T5Base {
public:
    //using T5Base::test1;
    //using T5Base::value;
    void test2() { cout << "value is " << value << endl; }
};

基类中成员变量 value 是protected,在 private 继承之后,对于外界这个值为 private,也就是说T5Derived 的对象无法使用这个 value。

如果想要通过对象使用,需要在public下通过 using T5Base::value 来引用,这样 T5Derived 的对象就可以直接使用。

同样的,对于基类中的成员函数 test1(),在private继承后变为 private,T5Derived 的对象同样无法访问,通过 using T5Base::test1 就可以使用了。

注意,using只是引用,不参与形参的指定。

函数隐藏case:

case3、 别名指定

using在c++11以后又有了一种新的作用,那就是与typedef一样,给类型指定别名,形式是这样的:

using 别名=类型;

我们把上面typedef那里的代码改一下,如下

对于函数指针,还可以这样:

using func = int (*)(int a, int b);

四、using 跟typedef有什么区别呢?哪个更好用些呢?

1、可读性

typedef std::unique_ptr<std::unordered_map<std::string, std::string>> UPtrMapSS;
using UPtrMapSS = std::unique_ptr<std::unordered_map<std::string, std::string>>;


typedef std::string (Foo::* fooMemFnPtr) (const std::string&);
using fooMemFnPtr = std::string (Foo::*) (const std::string&);

2、alias templates, 模板别名。

template <typename T>
using Vec = MyVector<T, MyAlloc<T>>;
 
// usage
Vec<int> vec;

这一切都会非常的自然。
那么,若你使用typedef来做这一切:

template <typename T>
typedef MyVector<T, MyAlloc<T>> Vec;
 
// usage
Vec<int> vec;

当你使用编译器编译的时候,将会得到类似:error: a typedef cannot be a template 的错误信息。

虽然两者都用于创建类型别名,但“typedef”的主要限制是它不适用于模板。当涉及到非模板工作时,“using”和“typedef”在机械上都是相同的。因此,在这种情况下,这是程序员的个人选择。

五、调用模板成员函数需不需要加template关键字

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1075344.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

根据二叉树创建字符串--力扣

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;强烈推荐优质专栏: &#x1f354;&#x1f35f;&#x1f32f;C的世界(持续更新中) &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;…

stm32 hal库 st7789 1.54寸lcd

文章目录 前言一、软件spi1.cubemx配置2.源码文件 二、硬件spi1.cubemx配置2.源码文件3.小小修改 总结 前言 1.54寸lcd 240*240 一、软件spi 1.cubemx配置 一定要注意把这几个东西上拉。 使用c8 2.源码文件 我使用的是中景园的源码&#xff0c;他本来是是标准库的稍微修改…

死灰复燃!QakBot 恶意软件仍在运行中

2023 年 8 月&#xff0c;美国联邦调查局宣布&#xff0c;在名为“猎鸭行动”的国际执法活动中&#xff0c;成功拆除 Qakbot 僵尸网络&#xff08;Qakbot 也称 QBot、QuackBot 和 Pinkslipbot&#xff0c;自 2008 年以来一直非常活跃&#xff09;。然而 Security A ffairs 网站…

好用的便签软件如何实现定时提醒?支持设定定时提醒的便签

不论你是职场白领&#xff1f;还是销售精英&#xff1f;亦或者是家庭主妇&#xff0c;每天都会面临着大量的事务需要处理&#xff0c;怎么才能高效规划管理自己每日事务&#xff0c;以及进行时间管理成为一项比较重大的挑战&#xff0c;便签类软件可以辅助大家按时完成各项任务…

Django REST framework API版本管理【通过GET参数传递】

API版本 在开发过程中可能会有多版本的API&#xff0c;因此需要对API进行管理。django drf中对于版本的管理也很方便。 http://www.example.com/api/v1/info http://www.example.com/api/v2/info 上面这种形式就是很常见的版本管理 在restful规范中&#xff0c;后端的API需…

基于安卓android微信小程序宠物交易小程序

运行环境 开发语言&#xff1a;Java 框架&#xff1a;ssm JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.3.9 小程序框架&…

七、全屏粒子特效

简介 给页面添加粒子光影特效。欢迎访问个人的简历网站预览效果 本章涉及修改与新增的文件&#xff1a;main.ts、App.vue、utils 一、安装插件 安装 vue3-particles tsparticles插件 详细文档查看 tsParticles 官网 npm i vue3-particlesnpm i tsparticles创建配置文件 o…

封装axios的post请求踩坑记录

今天自己封装axios请求时遇到了两个坑&#xff0c;所以记录一下。 第一个坑是我在代码的逻辑是只会发一次请求&#xff0c;但是在控制台却发现发了两次&#xff0c;第一次为不带参数的请求方式为options的预检请求&#xff0c;第二次的请求才是我真正需要发的post请求。在经过上…

基于Java+SpringBoot+Vue企业OA管理系统的设计与实现 前后端分离【Java毕业设计·文档报告·代码讲解·安装调试】

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

软件测试/测试开发丨利用ChatGPT 生成自动化测试脚本

点此获取更多相关资料 简介 自动化测试脚本可以模拟用户与应用程序的交互&#xff0c;例如点击按钮、输入数据、导航到不同的页面等等&#xff0c;以验证应用程序的正确性、性能和稳定性。 自动化测试在回归测试、冒烟测试等测试流程中都可以极大地起到节省时间、节省人力的作…

程序设计竞赛如何入门?

程序设计如何入门? 一、前言 对于刚接触竞赛的小白来说&#xff0c;了解以下几个问题至关重要。 程序设计竞赛难度如何&#xff1f;真小白怎么办&#xff1f;而且我数据结构什么的没上过或者学的很差怎么办&#xff1f;都说要刷题&#xff0c;但是怎么刷&#xff1f;刷多少…

QEMU背景知识

QEMU的两种模拟方案&#xff1a; 系统模拟 System Simulation&#xff1a;可以简单的理解为对整个计算机系统进行模拟&#xff08;CPU、Memory等&#xff09; 用户模式模拟 User Mode Simulation&#xff1a;基于模拟方案执行特定应用程序 除了模拟功能外&#xff0c;QUME工具…

如何巧用AI智能技术,让文物不再“无人问津”?

文物是文化与传统的象征&#xff0c;而博物馆则是展现文物的载体。传统的博物馆监控体系只是利用摄像头进行监控&#xff0c;无法将人工智能融入其中&#xff0c;使其更加智能化、信息化。那么&#xff0c;如何将AI技术与传统视频监控相融合呢&#xff1f;TSINGSEE青犀智能分析…

C++枚举(enum)

在本文中&#xff0c;您将学习使用枚举&#xff08;enum&#xff09;。此外&#xff0c;您还将学习C 编程中通常使用枚举的地方。枚举是用户定义的数据类型&#xff0c;由整数常量组成。可以使用关键字enum&#xff0c;定义枚举。 enum season { spring, summer, autumn, wint…

k8s简单部署nginx

文章目录 1. 前言2. 部署nginx2.1. **创建一个nginx的Deployment**2.2. **创建一个nginx的service** 3. 总结 1. 前言 前文提要&#xff1a; kubeadm简单搭建k8s集群第三方面板部署k8s 上篇文章我们简单部署了k8s的集群环境&#xff0c;相比一定迫不及待的想部署一个实际应用了…

底部Taber的抽取

1.会抽取一个布局样式 2.布局样式里面抽取一个底部样式 这个是layout的代码 <template><view class"layout-wrapper"><view class"layout-content"><slot></slot></view><!-- 底部 --><Tabbar :activeInde…

基于Java+SpringBoot+Vue宠物领养系统的设计与实现 前后端分离【Java毕业设计·文档报告·代码讲解·安装调试】

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

JVM源码剖析之线程的创建过程

说在前面&#xff1a; 对于Java线程的创建这个话题&#xff0c;似乎已经被"八股文"带偏&#xff5e; 大部分Java程序员从"八股文"得知创建Java线程有N种方式&#xff0c;比如new Thread、new Runnable、Callable、线程池等等&#xff5e; 而笔者写下这篇文…

Qemu系统模拟:1 简介

目录 1 后端/加速器2 特性简介3 运行 1 后端/加速器 系统模拟主要用于在host设备上运行guest OSQEMU支持多种hypervisors,同时也支持JIT模拟方案&#xff08;TCG&#xff09; 例如从上表我们可以看出&#xff0c;运行在x86硬件上的Linux系统支持KVM,Xen,TCG 2 特性简介 提供…

大数据集群(Hadoop生态)安装部署

目录 1. 简介 2. 前置要求 3. Hadoop集群角色 4. 角色和节点分配 5. 调整虚拟机内存 6. Zookeeper集群部署 7. Hadoop集群部署 7.1 下载Hadoop安装包、解压、配置软链接 7.2 修改配置文件&#xff1a;hadoop-env.sh 7.3 修改配置文件&#xff1a;core-site…