前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【C++11】让程序更简洁——模板

【C++11】让程序更简洁——模板

作者头像
CPP开发前沿
发布2022-03-03 11:10:09
6560
发布2022-03-03 11:10:09
举报
文章被收录于专栏:CPP开发前沿

C++11 改进了编译器的解析规则,尽可能的将多个“>”解析成模板参数结束符,方便了编写模板的相关代码。

一 模板的右尖括号(“>”)

在C++11之前,下面的这段代码在编译时将会报错,C++11之后,编译器将能够正常编译,代码如下:

代码语言:javascript
复制
template <typename T>
struct Foo{
typedef T type;
};

template <typename T>
class A{
  //
};
int main(){
  Foo<A<int>>::type t;
  return 0;
}

C98编译时,上述代码将会报错Foo<A<int>>这种写法将不被支持。需要写成如下格式:Foo<A<int> >;在C++11之后,这种限制已经被取消,编译器已经能够做出正确判断并进行编译。

二、模板的别名

在C98中,可以使用typedef重定义一个类型,如:

代码语言:javascript
复制
typedef unsigned int uint_t;

在上面的代码中无符号整型类型被重新定义,但并不是新增一种类型,只是给已存在的类型重新定义了一个别名。

如果重新定义一个模板时,使用typedef将会使代码变得复杂,增加了编码的复杂度,如:

代码语言:javascript
复制
template <typename Val>
struct str_map{
  typedef std::map<std::string,Val> type;
};

str_map<int> type_map;

上面的代码使用的是C98格式,需要额外增加一个壳,C++11种提供一个新的语法,上面的代码可以写成如下方式:

代码语言:javascript
复制
template <typename Val>
using str_map = std::map<std::string,Val>;
str_map<int> map1;

如上代码所示,C98和C++11实现的功能一样,但是C++11实现代码则更加简洁。

C++11的using语法提供的功能已经涵盖了typedef的所有功能,如在一开始定义的无符号整型的别名也可以这样定义:

代码语言:javascript
复制
using uint_t = unsigned int;

由此可以看出,typedef定义方法和变量声明类似,显示了C++语法的一致性,但是有时又会增加C++代码的阅读复杂度,如在对函数指针进行重定义时:

代码语言:javascript
复制
typedef void (*func_t)(int ,int);

使用using语法时,using紧接着的是标识符,和赋值语法类似,将一个现有的类型赋值给新的类型。和typedef相比,代码更清晰,易于阅读。

代码语言:javascript
复制
using func_t = void (*)(int,int);

下面在来看下如何使用using语法,实现为一个模板定义一个别名。大家可以留言回复使用C98语法如何为一个模板定义一个别名。

代码语言:javascript
复制
/*C++11*/
template <typename T>
using func_t= void (*) (T,T);
func_t<int> xx;

在这里需要注意的是:不管是typedef还是using,都不会新增一个类型,而是对原有类型进行重新定义一个别名。using语法更加强大,编写出的代码更加简洁。

三、函数模板的默认模板参数

在C98中,类模板可以有默认模板参数,函数模板中的默认模板参数是不被支持的,这一限制,在C++11中得到了解除。如下面代码所示:

代码语言:javascript
复制
template <typename R=int,typename U>
R func(U val){
  val
}
int main(){
  func(123);
  return 0;
}

值得注意的是,如果在使用函数模板时显示指定了模板参数的类型,函数的返回值将返回的是指定参数的类型。如:

代码语言:javascript
复制
func<long long>(123);//func的返回值为long long

还有一种使用方式是将函数模板默认参数和模板参数自动推导一起使用,在一起使用时,如果函数模板无法自动推导,将会使用默认模板参数,否则将使用自动推导出的参数类型。如下代码:

代码语言:javascript
复制
template <typeame T>
struct identity{
  typedef T type;
};

template <typename T = int>
void func(typename identity<T>::type val,T = 0){
  ///...
}

int main(){
  func(123);
  func(123,123.0);
  return 0;
}

在上面的代码中,通过identity禁用了val的自动推导,但因为指定了默认参数模板类型,因此,在func(123)中,func的val参数将为int整型,在func(123,123.0)中,第二个参数为浮点行,模板参数T将优先被推导,自动推导生效时,默认模板参数会被直接忽略。

<END>

如果大家有什么意见或者建议,请在下发评论留言。谢谢。

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

本文分享自 CPP开发前沿 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档