auto
auto 声明变量的类型必须由编译器器在编译时期推导而得
auto x = 1;
double foo();
auto y = foo(); // double
auto z; //error
z = x;
说明:
auto 并非一种“类型”声明,而是一个类型声明时的“占位符”,编译器器在编译时期会将auto替代为变量量实际的类型。
auto 推导的一个最大优势就是在拥有初始化表达式的复杂类型变量量声明时简化代码。
使用场景:
vector<int> v;
for (vector<int>::iterator it = v.begin(), end = v.end(); it != end; ++it) {
// 循环体
}
for (auto it = v.begin(), end = v.end();
it != end; ++it) {
// 循环体
}
lambda表达式
auto l = [] (int x) -> bool { return x > 0 };
具体使用细则: 见modern effective C++
declype
decltype 的用途是获得一个表达式的类型,结果可以跟类型一样使用
int i;
decltype(i) j = 0; // int
float a;
double b;
decltype(a + b) c; // double
应用场景:泛型编程
考虑模板函数求和
template<typename T1, typename T2>
double Sum(T1& t1, T2& t2)
{
auto s = t1 + t2;
return s;
}
上面返回值类型是个问题,利用decltype特性,可以修改如下:
template<typename T1, typename T2>
void Sum(T1& t1, T2& t2, decltype(t1 + t2)& s)
{
s = t1 + t2;
}
使用引用的方式将返回值出参,使用上仍然是个限制,直观上应该如下使用:
template<typename T1, typename T2>
decltype(t1 + t2) Sum(T1& t1, T2& t2)
{
return t1 + t2;
}
上述代码无法编译通过:编译器器却只会从左往右地读入符号;所以导致t1和t2未声明:
C++11引入新语法—追踪返回类型,来声明和定义这样的函数。
template<typename T1, typename T2>
auto Sum(T1& t1, T2& t2) -> decltype(t1 + t2)
{
return t1 + t2;
}
C++14开始:上诉代码可以直接写成:
template<typename T1, typename T2>
auto Sum(T1& t1, T2& t2)
{
return t1 + t2;
}
基于for的循环
int arr[5] = { 1, 2, 3, 4, 5 };
for(auto& e : arr)
{
e *= 2;
}
lambda表达式
lambda表达式==一个匿匿名函数,并且可以捕获一定范围内的变量。
lambda表达式 capture opt -> ret { body; }; ,capture是捕获列列表;params
是参数表;opt是函数选项;ret是返回值类型
auto sum = [](auto x, auto y){ return x + y;}
auto f = [](int a) -> int { return a + 1; };
auto f = [](int a){ return a + 1; };
// 省略略空参数表
auto f1 = [](){ return 1; };
auto f2 = []{ return 1; };
规则:
[] 不捕获任何变量量
[&] 捕获外部作用域中所有变量量,并作为引⽤用在函数体中使用(按引用捕获)
[=] 捕获外部作用域中所有变量量,并作为副本在函数体中使用(按值捕获)
[=,&foo] 按值捕获外部作⽤用域中所有变量量,并按引用捕获foo变量量
[bar] 按值捕获bar变量量,同时不不捕获其他变量量[this] 捕获当前类中的this指针,让lambda表达式拥有和当前类成员函数同样的访问权限。如果已经使用了&或者=,就默认添加此选项。捕获this的目的是可以在lamda中使⽤用当前类的成员函数和成员变量量
特殊地方:
按值捕获默认是不可对该值进行更改:
int id = 0;
auto f = [id] () mutable {
std::cout << "id: " << id << std::endl;
++id; // OK
};
id = 42;
class adder{
private:
mutable int id; // copy of outside id
public:
void operator() () const{
std::cout << "id: " << id << std::endl;
++id; // OK
}
};
典型应用场景,STL 需要函数对象的容器
#include <array> // std::array
#include <iostream> // std::cout/endl
#include <numeric> // std::accumulate
using namespace std;
int main()
{
array a{1, 2, 3, 4, 5};
auto s = accumulate(
a.begin(), a.end(), 0,
[](auto x, auto y) {
return x + y;
});
cout << s << endl;
}
静态断言
编译期检查
static_assert(编译期条件表达式, 可选输出信息);
template<typename T, typename U>
int bit_copy(T& a, U& b) {
static_assert(sizeof(a) == sizeof(b), "the parameters of bit_copy must have same width");
memcpy(&a, &b, sizeof(b));
}
自定义字面量
C++11 引入了自定义字面量,可以使用 operator"" 后缀 来将用户提供的字面量转换成实际的类型
#include <chrono>
#include <complex>
#include <iostream>
#include <string>
#include <thread>
using namespace std;
int main()
{
cout << "i * i = " << 1i * 1i << endl;
cout << "Waiting for 500ms" << endl;
this_thread::sleep_for(500ms);
cout << "Hello world"s.substr(0, 5)<< endl;
}
要在自己的类里支持字面量,唯一的限制是非标准的字面量后缀必须以下划线 _ 打头。比如,假如我们有下面的长度类:
struct length {
double value;
enum unit {
metre,
kilometre,
millimetre,
centimetre,
inch,
foot,
yard,
mile,
};
static constexpr double factors[] =
{1.0, 1000.0, 1e-3,
1e-2, 0.0254, 0.3048,
0.9144, 1609.344};
explicit length(double v,
unit u = metre)
{
value = v * factors[u];
}
};
length operator+(length lhs, length rhs)
{
return length(lhs.value + rhs.value);
}
// 可能有其他运算符
我们希望实现下面的表达式运算:
1.0_m + 10.0_cm
要允许上面这个表达式,我们只需要提供下面的运算符即可
length operator"" _m(long double v)
{
return length(v, length::metre);
}
length operator"" _cm(long double v)
{
return length(v, length::centimetre);
}
default 和 delete 成员函数
#include <iostream>
class my_array {
public:
my_array() = default;
my_array(const my_array &) = delete;
my_array(size_t size);
size_t getSize() { return size_; }
private:
int* data_{nullptr};
size_t size_{0};
};
int main()
{
my_array array;
std::cout<<array.getSize();
return 0;
}
override 和 final 说明符
class A {
public:
virtual void foo();
virtual void bar();
void foobar();
};
class B : public A {
public:
void foo() override; // OK
void bar() override final; // OK
//void foobar() override; // 非虚函数不能 override
};
class C final : public B {
public:
void foo() override; // OK
//void bar() override;
// final 函数不可 override
};
class D : public C {
// 错误:final 类不可派生
…
};