在C++11之前,一个经典的看法是C++可以分为4个部分,C、面向对象、STL和模板,它们既有内在联系,又相对独立(《Effective C++》)。不过在C++11之后,它们之间的联系更紧密了,更像是一门语言,而不是四门语言。所以,如果要找C++版本更新的脉络的话,我更愿意把它分为3个部分:语言特性、标准库、模板。
在语法部分里,C++的历次更新中引入了auto类型推断、引入了constexpr编译时常量表达式和分支语句、引入了lambda闭包函数,还引入了结构绑定、折叠表达式、初始化列表、类内的using语法等等。同时一些新的结构替换或者补充了旧的C的中的模式,比如variant、string_view、array、tuple、智能指针等。
这一部分的更新,与其说是更新,不如说是在追赶。毕竟从03到11,编程语言的发展速度超乎远超世纪之初程序员的想象,特别是Java、C#、Python等语言,它们在快速地更新中引入了大量的新的语法和特性,不仅提升了语言的易用性,也吸引了越来越多的开发者。C++历次版本对语法的更新,你总能在市面上流行的语言中找到一些痕迹,甚至你可以直接说出它们是从哪里抄过来的,有一些抄的比较巧妙,有一些抄的非常丑(tuple相关的设计出来挨打,把python的脸都丢尽了)。
当然了,由于C++亲近底层,这些更新即使能够在其他语言中找到对照,但是依然是很具有语言特色。比如,lambda需要自己设置捕获哪些变量以及捕获方式,auto类型推断具有模板的作用,tuple类型是编译时的,等等。还有一些是C++自身的特色,比如右值引用和移动语义,这些内容尽管非常重要,但其他语言的程序员可能从未见过。
对于这些更新,由于逻辑性不强,只能试着用用,用着用着,如果好用,那么就熟悉了,不好用的语法大家也不会广泛使用,有个印象就好,没有必要为了准赶时髦而故意用一些新奇的语法。当然,对于重要的内容还是需要掌握的,特别是auto、lambda、右值引用、constexpr等。
STL的更新是每一次版本更新中对于普通开发者而言最重要的部分。C++简陋的标准库一直被诟病,连多线程、网络都没有,甚至哈希表都是残疾的。别的语言标准库中的内容,到了C++中竟然还需要引入第三方库来实现。
C++11~20在标准库方面也是在不断的追赶,比如引入了原子操作库、时间库、随机数库、多线程支持、格式化字符串(C++20才引入)、特殊数学函数库(这种东西C++17居然就有了),当然了网络库还在难产中。
这一部分对于普通C++用户而言,当然是天大的福利。写出来的程序可以使用更少的第三方库,并且更容易的跨平台,曾经为了格式化字符串而引入一个boost库的日子一去不复返了(也难说)。
这一部分其实也没有什么逻辑,但是用户并不需要为此担心,因为用到了查一查自然就会用了,用不到的你也不需要了解。了解这些内容,主要目的是心中大概知晓C++标准库有哪些内容,哪些内容需要引入第三方库。
对于库开发者而言,模板其实才是重头戏。这一部分的更新相当有逻辑,因为C++03的模板太残疾了。尽管C++03的模板很强大,是图灵完全的[1],但是由于对类型没有约束,编译时错误很难被提前检测,以至于用户会一脸懵逼的看着一个类型错误导致的100多行编译报错,然后怒换语言(然后发现因为库依赖,换不了)。所以,整个C++11~20,对于模板的主要改进方向就是类型支持,以及让模板更好写。
第一个重要的变化是类型限制。C++11引入了各种标准的traits和enable_if,通过SFINAE对模板类型进行限定。这个时候,库作者可以指定模板能够接受哪些类型,或者哪个类型的子类,基本上实现了Java中模板的类型限定功能,并且还增加了许多新的玩法。不过这个版本的主要问题是enable_if语法十分冗长,为了做好一个模板的模板参数限定,会写出非常难看的语句,并且报错依旧还是很难看。C++20改进了这一做法,限定模板类型可以使用更为优雅的Concept的语法,报错的行数也可以从100多行减少到两三行。
其次是类型推断。由于C++模板套模板,所以一个对象的实际类型的完整表达往往非常扭曲,一个别名的背后可能是上百个ascii字符组成的名字。以前,程序员是需要自己来写这些名字的。C++11引入了auto和decltype,允许编译器对类型进行推断,解放了程序员的双手,减少了划水的理由。
另一套有点意思的是变参模板,这个语法最开始需要递归解参数包,尽管可以使用,但是写法非常扭曲。直到C++17引入了折叠表达式和if constexpr之后,写法才变得正常了许多。
上述三项当然没有完全涵盖所有的更新,但是大体上可以给C++近年来的更新画出一个脉络——基本没有脉络。尽管细节部分有一些逻辑,但是总体上看内容繁杂,一团乱麻。所以,读者面对一大堆散乱的更新没有必要一口气吃成个胖次,更多的是学中用,用中学,不必焦虑,毕竟很多公司还停留在C++03和C with Class呢。
网络文献
C++ Reference: https://en.cppreference.com/
现代C++教程:https://changkun.de/modern-cpp/
纸质书