技术收藏程序员首页推荐

C++11类型系统

2016-09-28  本文已影响591人  刘光聪

C++ feels like a new language. -- Bjarne Stroustrup

  1. 类型推演
  2. 右值引用
  3. 通用引用
  4. 剖析std::move
  5. 剖析std::forward
  6. 总结

类型推演

增强了的「类型系统」是C++11最大的优化亮点之一,为此需要深入剖析「类型推演」的工作机理,并能灵活地运用auto, decltype,这是C++11最重要的基石。

template与auto

C++98早已具备类型推演的能力,用于模板的类型推演。

C++11中,autotemplate的类型推演能力基本类似,只存在唯一的差异:Braced Initialization,或称为Universal Initialization

非常量的左值引用

需要注意的是,推演auto &r2 = r, auto &cr2 = cr时,即使r(int&), cr(const int&)是引用变量,需要去除引用后再尝试类型推演,因为使用「引用变量」等价于使用其「引用对象」本身。

常量的左值引用

因为const T&const auto&已经具备了const的属性,当const的左值对象赋予它所发生的自动类型推演,其模板参数T,及其auto的类型无需推演为const属性。


指向非常量的指针

指针的推演能力与引用类似。

需要注意auto *p = &i; auto p = &i两种写法的不一样,一种是显式的指针类型,另外一种完全依赖于auto的类型推演能力。

指向常量的指针

与指向非常量的指针推演机制一致,在此不再冗述。


按值传递

Pass-By-Value,经过拷贝之后,两者之间已无任何瓜葛,为此const的处理机制有别于其他情况。



但存在两类特殊的,遗留的C-Style情况,为保证兼容性,存在特殊的类型推演机制。

遗留的C-style字符串

遗留的C-style函数

通用引用:Universal Reference

所谓Universal Reference,因为其能Can bind to anything,所以称为「通用引用」,具有如下方面的特点:

需要注意的是,Universal Reference并非「右值引用(Rvalue Reference)」,即使它们两者都有类似的T &&的修饰符。规则非常简单,Universal Reference具备两个最基本的特征:

可以简单归纳之,Universal Reference出现于如下两种常见:

template <typename T>
void f(T&& t);

auto&& r = i;

Universal Reference类型推演也存在特殊性:



通用初始化:Braced Initialization

这是templateauto类型推演能力之间存在的唯一差别。

右值引用

「右值引用」(Rvalue Reference) 与「通用引用」(Universal Reference)是两个不同的概念,非常容易混淆,本文试图揭示两者之间的本质的差异。

左值与右值

「左值」与「右值」并非C++11的产物,早已是C++类型系统的一部分了,并且两者之间存在明显的区别。

举个例子,进一步明细两者之间的差异。此处使用auto&&Universal Reference,它会根据「左值」自动推演为「左值引用」,而「右值」推演为「右值引用」。

右值引用

C++98中,只存在「左值引用」,遗恨缺失「右值引用」的概念,也因此丢失了部分性能优化的空间。C++11中引入了「右值引用」,弥补之前的过失,结合「移动」(move)的机制,进一步提高了C++在特殊场景的性能。

所谓右值引用,即「右值」的引用;之前惯称的「引用」,其实是「左值引用」的简称。「左值引用」只能引用「左值」,「右值引用」只能引用「右值」。

通用引用

「通用引用」并非「左值引用」,即使它们之间都具有&&的语法结构。「通用引用」即可以持有「左值」,也可以持有「右值」,是一种「通用」的引用类型。而「右值引用」只能引用「右值」。

特征

可以简单归纳之,「通用引用」出现于如下两种常见:

template <typename T>
void f(T&& t);

auto&& r = i;

样例

std::vector新增加的「右值引用」的push_back,及其「通用引用」的emplace_back是最好的案例。

剖析std::move

C++11实现

当传递左值时

经过如下的类型推演过程,当传递「左值」时,std::move强制转为换「右值引用」。

当传递右值时

经过如下的类型推演过程,当传递「右值」时,std::move顺水推舟,传递「右值引用」。综上述,借助「通用引用」的能力,std::move其实完成了「无条件的」右值引用转换规则。

C++14改进实现

剖析std::forward

C++11实现

当传递左值时

经过如下的类型推演过程得知,当传递「左值」时,std::forward完成「左值」的「转发」机制。

当传递右值时

经过如下的类型推演过程得知,当传递「右值」时,std::forward也完成「右值」的「转发」机制。为此,std::forward的机制,完成了C++11的「完美转换」(Perfect Forward)的机制。

C++14改进实现

习惯用法

回顾

上一篇 下一篇

猜你喜欢

热点阅读