Note:编译时使用-std=c++17编译标志。
Note:example code见https://github.com/BarretRen/CppCodeCollections
Note:参考资料https://github.com/changkun/modern-cpp-tutorial
1530257061238.png

1. 被弃用的特性

  1. C 语言风格的类型转换被弃用(即在变量前使用 (convert_type)) ,应该使用static_cast、 reinterpret_cast、 const_cast 、dynamic_cast来进行类型转换。
  2. 在编写 C++ 时,也应该尽可能的避免使用诸如 void* 之类的程序风格。在不得不使用C时,应该注意使用extern “C” 这种特性,将 C 语言的代码与 C++ 代码进行分离编译,再统一链接的做法。example_1 code

2. nullptr

替代NULL(0),代表空指针。nullptr 的类型 为 nullptr_t,能够隐式的转换为任何指针或成员指针的类型,也能和他们进行相等或者不等的比较。

原因: 将NULL定义为0会是C++重载特性出现混乱:

  1. void foo(char*);
  2. void foo(int);
  3. //当调用foo(NULL)时,实际调用的是foo(int), 代码违反直觉。

例子example_2 code

  1. #include <iostream>
  2. #include <type_traits>
  3. void foo(char *);
  4. void foo(int);
  5. int main()
  6. {
  7. if (std::is_same<decltype(NULL), decltype(0)>::value)
  8. std::cout << "NULL == 0" << std::endl;
  9. if (std::is_same<decltype(NULL), decltype((void*)0)>::value)
  10. std::cout << "NULL == (void *)0" << std::endl;
  11. if (std::is_same<decltype(NULL), std::nullptr_t>::value)
  12. std::cout << "NULL == nullptr" << std::endl;
  13. foo(0);
  14. foo(nullptr);
  15. //foo(NULL); 编译失败
  16. return 0;
  17. }
  18. void foo(char *)
  19. {
  20. std::cout << "foo (char *) is called" << std::endl;
  21. }
  22. void foo(int i)
  23. {
  24. std::cout << "foo (int) is called" << std::endl;
  25. }

3 原生字符串r

C++11开始提供了和Python中r关键字一样的R关键字,可以使字符串中的特殊字符失效,让编译器当作普通的原始字符串,对于文件路径等字符串非常关键。
原生字符串格式为:R"(字符串内容)",例如:
std::string str = R"(C:\\What\\The\\Path )";

4 字符串编码

如下编码标志可以指定字符串的编码类型:

  • u8:UTF-8编码,对应类型为const char
  • u:char16_t.
  • U:char32_t.
  • L:wchar_t

    5 noexcept

    noexcept作为函数的后缀,表示该函数不会抛出异常。例如:void foo() noexcept;

    6 constexpr

    C++11 提供了 constexpr 让用户显式的声明运算、函数或对象构造函数在编译阶段就计算出结果
    从 C14 开始, 移除了一些限制,constexptr 函数可以在内部使用局部变量、循环和分支等简单语句。C14之前必须是一个return表达式,不然编译会出错。

    用法

  • constexpr 变量constexpr int theAnswer= 10 + 20 + 12; 变量为const常量,在编译时被赋初值

  • constexpr 函数:表示函数在编译阶段就可以调用返回结果。比如可以用到上面的constexpr变量赋值。
  • constexpr 类:类的成员函数和构造函数也可以用constexpr修饰,但要注意不能有虚成员函数(编译时没有多态)
    • constexpr成员函数可以调用其他constexpr函数
    • constexpr构造函数可以为成员指定常量值
  • 模板变量:模板中的变量和函数也能使用constexpr ```cpp template constexpr T pi = T(3.1415926535897932384626433L);

template constexpr T computeCircumference(const T radius) { return 2 radius pi; }

  1. <a name="wa0e2"></a>
  2. ## constexpr函数例子
  3. ```cpp
  4. #include <iostream>
  5. //constexpr函数,编译期间可以返回结果
  6. constexpr unsigned long long factorial(const unsigned short n) {
  7. return n > 1 ? n * factorial(n - 1) : 1;
  8. }
  9. int main() {
  10. unsigned short number = 6;
  11. auto result1 = factorial(number);//正常调用,需要运行时才计算结果
  12. constexpr auto result2 = factorial(10);//constexpr变量,在编译时就得到结果
  13. std::cout << "result1: " << result1 << ", result2: " << result2 << std::endl;
  14. return 0;
  15. }

再比如,我们想动态的创建一个数组,但编译器需要在编译期间就指定数组的大小。这时候可以使用constexpr完成:

  1. //constexpr函数,编译期间可以返回结果
  2. constexpr int getArraySize(int a)
  3. {
  4. return 32 + a;
  5. }
  6. int main()
  7. {
  8. constexpr int a{ 8 };
  9. int myArray2[getArraySize(a)]; // 函数在编译期可以调用返回32+a
  10. }

constexpr类例子

构造函数和成员函数指定为constexpr,就可以在编译期创建constexpr类的对象,并使用类的函数。
再以创建数组为例:

  1. class Rect
  2. {
  3. public:
  4. constexpr Rect(size_t width, size_t height) : m_width { width }, m_height { height } {}
  5. constexpr size_t getArea() const { return m_width * m_height; }
  6. private:
  7. size_t m_width { 0 }, m_height { 0 };
  8. };
  9. //创建对象
  10. constexpr Rect r { 8, 2 };//调用constexpr构造函数
  11. int myArray[r.getArea()];

7 consteval

C++20新增了consteval关键字,用来修饰函数时常量值的表达式,而且是强制性的。如果函数本身不是常量值的表达式的话则会编译失败。被修饰的函数变为立即函数。