前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >c++中typename、typedef以及using关键字用法

c++中typename、typedef以及using关键字用法

作者头像
cpp加油站
发布2021-06-07 15:26:40
8980
发布2021-06-07 15:26:40
举报
文章被收录于专栏:cpp加油站cpp加油站

在c++的标准库中,因为类继承关系比较复杂和模板使用比较多的原因,源代码中充斥着typename、typedef和using这三个关键字,所以在继续剖析标准库源码之前,今天就来介绍一下这三个关键字的作用。

一、typename关键字

typename的第一个作用是用作模板里面,来声明某种类型,比如这样的:

代码语言:javascript
复制
template<typename _Tp, typename _Alloc>
    struct _Vector_base;

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

typename在stl中还有另外一种作用,假设有这样一段代码:

代码语言:javascript
复制
//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看,会发生什么呢?

再次编译,报错如下:

代码语言:javascript
复制
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就是为了告诉编译器,它后面的一大串字符串都是一个类型。

二、typedef关键字

还是这段代码,我们添加一行:

代码语言:javascript
复制
#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;
    _Tp_alloc_type tp;
};

这个typedef实际上就是给类型取了一个别名,将__gnu_cxx::__alloc_traits<_Alloc>::template rebind<_Tp>::other这么一长串的类型取了一个简单的别名,要是不取别名,这样长的类型真的是不忍直视。

当然啦,typedef除了这种形式以外,其实很多时候也会给函数指针取别名哦,如下:

代码语言:javascript
复制
typedef int (*func)(int a, int b);

这个时候实际上就是给int * (int a, int b)这个函数指针取了一个别名func。

三、using关键字

对于using关键字,最开始知道是因为这行代码:

代码语言:javascript
复制
using namespace std;

所以它的第一个作用就是声明命名空间,使用形如using namespace 命名空间名;这样的形式告诉编译器,后续使用该命名空间里面的变量或者类型都无需再加上std的前缀,这个是对于命名空间整体的声明。

还有一种形式是:

代码语言:javascript
复制
using std::cout;
using std::endl;

这种就是只单独声明命名空间里面的某个名字,命名空间里面其他的东西是无法直接使用的,此时我们只能使用cout和endl这两个。

using的第三种使用形式是:

代码语言:javascript
复制
class parent
{
protected:
    int m;
};

class child: public parent
{
public:
    using parent::m;
};

int main()
{
    child c;
    c.m = 2;
    return 0;
}

m在parent里面是protected类型,但是在child里面使用using声明以后,它可以被直接访问,其实这个时候它的作用类似于引入命名空间中的变量,此处是引入父类中的保护类型成员变量,对于这种用法,我们不展开多说,只要知道有这样的作用,以后看到了这样的代码知道它是怎么个意思就行了。

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

代码语言:javascript
复制
using 别名=类型;

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

代码语言:javascript
复制
#include <ext/alloc_traits.h>
using namespace std;

template<typename _Tp, typename _Alloc>
class AA
{
    using  _Tp_alloc_type = typename __gnu_cxx::__alloc_traits<_Alloc>::template rebind<_Tp>::other;
    _Tp_alloc_type tp;
};

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

代码语言:javascript
复制
using func = int (*)(int a, int b);

这样看来,using感觉上比typedef更加直观一下哈。

好了,关于三个关键字的简单介绍就到这里了,下篇文章再会呀。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-06-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 cpp加油站 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、typename关键字
  • 二、typedef关键字
  • 三、using关键字
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档