有关auto
函数值可以返回auto
auto
关键字可以用于函数返回值推导和lambda表达式参数列表的类型推导
| template<typename T> auto foo(T t) { return t; }
|
甚至这样也可以:有一个退出路径返回了具体类型:
| auto fabonaci(int n) { if (1 == n || 2 == n) return 1; return fabonaci(n - 1) + fabonaci(n - 2); }
|
可以实现泛型lambda
| struct unnamed_lambda { template<typename T, typename U> auto operator()(T x, U y) const {return x + y;} }; auto lambda = unnamed_lambda();
|
现在泛型lambda十分简单:
| auto lambda = [](auto x, auto y) {return x + y;};
|
Generalized lambda capture
| unique_ptr<int>b = std::make_unique<int>(5); auto fun = [x = std::move(b)](int t = 5) { cout<<*x<<endl; }; fun();
|
更宽松的constexpr
constexpr 最常用的用法就是修饰函数
如下所示,用 constexpr 来修饰一个函数。C++11 中的 constexpr 指定的函数返回值和参数必须要保证是字面值,而且必须有且只有一行 return 代码,这给函数的设计者带来了更多的限制,通常只能通过 return 三目运算符 + 递归来计算返回值,如下例所示。
| constexpr int factorial(int n) { return n <= 1 ? 1 : (n * factorial(n - 1)); }
|
C++14 对于 constexpr 的改进
而 C++14 中只要保证返回值和参数是字面值就行了,函数体中可以加入更多的语句,方便了更灵活的计算和复杂功能的实现。
| constexpr int factorial(int n) { int ret = 0; for (int i = 0; i < n; ++i) { ret += i; } return ret; }
|
变量模板
| template<typename T> constexpr T pi() { return T(3.1415926535897932385); }
|
std::make_unqiue
为了配对make_shaderd
std::exchange
std::swap()
才是真正的交换,两个元素的值进行了互换。
| template<typename _Tp> constexpr inline void swap(_Tp& __a, _Tp& __b) { _Tp __tmp = std::move(__a); __a = std::move(__b); __b = std::move(__tmp); }
|
读写锁
什么是互斥锁和读写锁:
互斥锁,是只同一时刻只能有一个线程获得锁,其余尝试加锁的线程都处于阻塞状态。而相比于互斥锁的两种状态(锁住和未加锁),读写锁可以有三种状态,即读模式加锁、写模式加锁和未加锁。只有一个线程可以处于写模式加锁状态,但是可以有多个线程同时处于读模式加锁状态。
锁状态 |
加读锁 |
加写锁 |
写模式加锁状态 |
失败 |
失败 |
读模式加锁状态 |
成功 |
失败 |
未加锁状态 |
成功 |
成功 |
- 读写锁又称为共享-独占锁。写锁是独占的,其余加锁行为都会阻塞;读锁是共享的,多个线程可同时获得读锁,但加写锁会阻塞。
- 现代C++提供了
std::shared_mutex(C++17)
和std::shared_timed_mutex(C++14)
两种共享互斥量,又提供了std::shared_lock(C++14)
和std::unique_lock(C++11)
共同管理这类互斥量来实现读写锁。
std::shared_lock
只是对共享互斥量的一种包装器,提供了更加安全方便的调用操作。
举个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| #include <iostream> #include <shared_mutex> #include <thread> #include <chrono>
void test_shared_lock() { int num = 0; std::shared_mutex mtx;
auto reading = [&]() { for (int i = 0; i < 3; ++i) { std::shared_lock<std::shared_mutex> lck(mtx); std::cout << std::this_thread::get_id() << " reading: " << num << std::endl; } };
auto writing = [&]() { for (int i = 0; i < 3; ++i) { std::unique_lock<std::shared_mutex> lck(mtx); std::cout << std::this_thread::get_id() << " writing: " << ++num << std::endl; } };
std::thread r1(reading); std::thread w1(writing); std::thread r2(reading); std::thread w2(writing);
r1.join(); w1.join(); r2.join(); w2.join(); }
void test_shared_lock_for() { int num = 0; std::shared_timed_mutex mtx;
auto reading = [&]() { for (int i = 0; i < 3; ++i) { std::shared_lock<std::shared_timed_mutex> lck(mtx, std::chrono::milliseconds(10)); std::cout << std::this_thread::get_id() << " reading: " << num << std::endl; } };
auto writing = [&]() { for (int i = 0; i < 3; ++i) { std::unique_lock<std::shared_timed_mutex> lck(mtx, std::chrono::milliseconds(10)); std::cout << std::this_thread::get_id() << " writing: " << ++num << std::endl; } };
std::thread r1(reading); std::thread w1(writing); std::thread r2(reading); std::thread w2(writing);
r1.join(); w1.join(); r2.join(); w2.join(); }
void test_shared_lock_until() { int num = 0; std::shared_time_mutex mtx;
auto reading = [&]() { for (int i = 0; i < 3; ++i) { std::shared_lock<std::shared_timed_mutex> lck(mtx, std::chrono::time_point<std::chrono::high_resolution_clock>(std::chrono::milliseconds(10))); std::cout << std::this_thread::get_id() << " reading: " << num << std::endl; } };
auto writing = [&]() { for (int i = 0; i < 3; ++i) { std::unique_lock<std::shared_timed_mutex> lck(mtx, std::chrono::time_point<std::chrono::high_resolution_clock>(std::chrono::milliseconds(10))); std::cout << std::this_thread::get_id() << " writing: " << ++num << std::endl; } };
std::thread r1(reading); std::thread w1(writing); std::thread r2(reading); std::thread w2(writing);
r1.join(); w1.join(); r2.join(); w2.join(); }
int main() { test_shared_lock(); return 0; }
|
std::integer_sequence
https://zhxilin.github.io/post/tech_stack/1_programming_language/modern_cpp/cpp14/more_cpp14/#stdinteger_sequence
常见的用法是遍历tuple,更多的用处是配合C++17的折叠表达式
| template <typename Tuple, typename Func, size_t ... N> void func_call_tuple(const Tuple& t, Func&& func, std::index_sequence<N...>) { static_cast<void>(std::initializer_list<int>{(func(std::get<N>(t)), 0)...}); }
template <typename ... Args, typename Func> void travel_tuple(const std::tuple<Args...>& t, Func&& func) { func_call_tuple(t, std::forward<Func>(func), std::make_index_sequence<sizeof...(Args)>{}); }
int main() { auto t = std::make_tuple(1, 4.56, "happen lee"); travel_tuple(t, [](auto&& item) { std::cout << item << ","; }); }
|
二进制字面量
| auto a1 = 42; auto a2 = 0x2A; auto a3 = 0b101010;
int a = 0b0001'1001'0001; double b = 3.141'5926'5358'9793'2385;
|
[[deprecated]标记
让编译产生警告
| #include <iostream>
void [[deprecated]] f() { std::cout << "f()" << std::endl; }
int main() { f(); }
|
std::quoted
C++14引入std::quoted
用于给字符串添加双引号
| std::cout<<std::quoted(mystring);
|