本文介绍C++ 11及后续版本中的新特性

1 C++ 11新增关键字(部分)

1.1 constexpr

constexpr 和const的功能类似,只值 constexpr 类型在编译时会进行变量类型检查,检查变量的值是否为常量表达式。
声明为 constexpr的变量一定是常量,而且必须使用常量表达式初始化

1.2 decltype

decltype的作用是获取并返回操作数的类型。
针对的场景:希望从表达式的类型推导出要定义的变量的类型,但是不想用该表达式初始化变量。例如:

1
2
const int ci = 0;
decltype(ci) x = 1; // x的类型为const int

1.3 =default

= default是用于限定构造函数的,要求编译器生成构造函数。它可以出现在类内部,也可以作为定义出现在类外部。 若在类内部,则默认构造函数是内联的,如果在内外部,则该构造函数默认不是内联的。

1.4 =delete

用于修饰函数,将函数定义为已删除。所有尝试调用已删除函数的代码,都会在编译阶段报错。

1.5 noexcept

用于指定函数不抛出异常。

1.6 nullptr

nullptr是一个指针常量,表示空指针。

1.7 explicit

1.7.1 修饰构造函数

explicit用于修饰构造函数是,用于阻止构造函数进行隐式转换。
explicit只对拥有一个参数的构造函数有效。 explicit只能在类内部声明构造函数时使用,而且在类外定义该构造函数时不能重复使用该关键字。 explicit声明构造函数时,该构造函数只能安札直接初始化的形式使用。

1.8 override

override关键字用在派生类的函数中,用于明确覆盖基类中的同名函数。
若要在派生类的函数中使用override关键字,需要基类中有同名函数而且该函数为虚函数(virtual修饰)。【只有虚函数才能被覆盖】。 final和override说明符出现在形参列表(包括任何const或引用修饰符)以及尾置返回类型之后。

1.9 final

final的作用是阻止派生类覆盖该函数。 当函数使用final修饰后,任何尝试覆盖该函数的操作都会报错。

1.10 auto

1.11 using

using可以用来声明类型别名和模板声明别名。
示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// type alias, identical to
// typedef std::ios_base::fmtflags flags;
using flags = std::ios_base::fmtflags;
// the name 'flags' now denotes a type:
flags fl = std::ios_base::dec;
 
// type alias, identical to
// typedef void (*func)(int, int);
using func = void (*) (int, int);
// the name 'func' now denotes a pointer to function:
void example(int, int) {}
func f = example;

// type alias used to hide a template parameter 
template<class CharT>
using mystring = std::basic_string<CharT, std::char_traits<CharT>>;
mystring<char> str;

2 Lambda表达式

2.1 Lambda表达式的几种模式

1
2
3
4
//[ capture-list ] ( params ) mutable(optional) constexpr(optional)(c++17) exception attribute -> ret { body }  (1)   
//[ capture-list ] ( params ) -> ret { body }  (2)   
//[ capture-list ] ( params ) { body }  (3)   
//[ capture-list ] { body }  (4)
  • capture-list - a comma-separated list of zero or more captures, optionally beginning with a capture-default.
    Capture list can be passed as follows (see below for the detailed description):

    [a,&b] where a is captured by copy and b is captured by reference.
    [this] captures the current object (*this) by reference
    [&] captures all automatic variables used in the body of the lambda by reference and current object by reference if exists
    [=] captures all automatic variables used in the body of the lambda by copy and current object by reference if exists
    [] captures nothing

  • params - The list of parameters, as in named functions, except that default arguments are not allowed (until C++14). If auto is used as a type of a parameter, the lambda is a generic lambda. (since C++14)

  • ret - Return type. If not present it’s implied by the function return statements (or void if it doesn’t return any value)

  • body - Function body

2.2 Lambda表达式的示例程序

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
 
int main()
{
    std::vector<int> c = {1, 2, 3, 4, 5, 6, 7};
    int x = 5;
    c.erase(std::remove_if(c.begin(), c.end(), [x](int n) { return n < x; }), c.end());
 
    std::cout << "c: ";
    std::for_each(c.begin(), c.end(), [](int i){ std::cout << i << ' '; });
    std::cout << '\n';
 
    // the type of a closure cannot be named, but can be inferred with auto
    auto func1 = [](int i) { return i + 4; };
    std::cout << "func1: " << func1(6) << '\n';
 
    // like all callable objects, closures can be captured in std::function
    // (this may incur unnecessary overhead)
    std::function<int(int)> func2 = [](int i) { return i + 4; };
    std::cout << "func2: " << func2(6) << '\n';
}

程序执行结果:

c: 5 6 7
func1: 10
func2: 10