Modern Cpp Tutorial笔记

浏览github上modern cpp tutorial时记录下的笔记

Chapter1

The string literal constant is no longer allowed to be assigned to a char *. If you need to assign and initialize a char * with a string literal constant, you should use const char * or auto.

如果混用C和C++,应对C代码做额外处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// foo.h
#ifdef __cplusplus
extern "C" {
#endif

int add(int x, int y);

#ifdef __cplusplus
}
#endif

// foo.c
int add(int x, int y) {
return x+y;
}

并在编译时先单独编译C代码,再链接到cpp代码上。

Chapter 2

C++ does not allow to implicitly convert void * to other types. The type of nullptr is nullptr_t, which can be implicitly converted to any pointer or member pointer type, and can be compared equally or unequally with them.

Starting with C++14, the constexpr function can use simple statements such as local variables, loops, and branches internally.

the function of constexpr can use recursion

C++17 if的括号里也可以定义变量了

structured binding

C++17提供了方便的tuple。

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <tuple>

std::tuple<int, double, std::string> f() {
return std::make_tuple(1, 2.3, "456");
}

int main() {
auto [x, y, z] = f();
std::cout << x << ", " << y << ", " << z << std::endl;
return 0;
}

类型推导

1
auto arr = new auto(10); // arr as int *

C++20甚至支持函数参数用auto

1
2
3
4
5
6
7
int add(auto x, auto y) {
return x+y;
}

auto i = 5; // type int
auto j = 6; // type int
std::cout << add(i, j) << std::endl;

auto不能用于数组类型的推导

1
auto auto_arr2[10] = {arr};   // illegal, can't infer array type

使用std::is_same<decltype(x), int>::value判断类型是否相同

c++11模板函数返回类型的推导需要如下

1
2
3
4
template<typename T, typename U>
auto add2(T x, U y) -> decltype(x+y){
return x + y;
}

C++14则可以用auto直接推导。

1
2
3
4
template<typename T, typename U>
auto add3(T x, U y){
return x + y;
}

In simple terms, decltype(auto) is mainly used to derive the return type of a forwarding function or package, which does not require us to explicitly specify the parameter expression of decltype

1
2
std::string  lookup1();
std::string& lookup2();

在c++11中

1
2
3
4
5
6
std::string look_up_a_string_1() {
return lookup1();
}
std::string& look_up_a_string_2() {
return lookup2();
}

c++14

1
2
3
4
5
6
decltype(auto) look_up_a_string_1() {
return lookup1();
}
decltype(auto) look_up_a_string_2() {
return lookup2();
}

if constexpr

常用于模板函数


C++11引入了extern templates以避免过多重复实例化

1
2
template class std::vector<bool>;          // force instantiation
extern template class std::vector<double>; // should not instantiation in current file

typedef不支持模板参数,但using支持

1
2
3
// not allowed
template<typename T>
typedef MagicType<std::vector<T>, std::string> FakeDarkMagic;

Variadic templates

1
template<typename... Ts> class Magic;
1
template<typename... Args> void printf(const std::string &str, Args... args);

使用sizeof...()获取参数个数

1
2
3
4
5
6
7
template<typename T, typename... Ts>
auto printf3(T value, Ts... args) {
std::cout << value << std::endl;
(void) std::initializer_list<T>{([&args] {
std::cout << args << std::endl;
}(), value)...};
}

为了解包,一种标准方式为递归

1
2
3
4
5
6
7
8
9
10
11
12
13
template<typename T0>
void printf1(T0 value) {
std::cout << value << std::endl;
}
template<typename T, typename... Ts>
void printf1(T value, Ts... args) {
std::cout << value << std::endl;
printf1(args...);
}
int main() {
printf1(1, 2, "123", 1.1);
return 0;
}

但是利用sizeof...可以更方便地实现

1
2
3
4
5
template<typename T0, typename... T>
void printf2(T0 t0, T... t) {
std::cout << t0 << std::endl;
if constexpr (sizeof...(t) > 0) printf2(t...);
}

还有一种方式是利用fold expression

1
2
3
4
5
6
7
template<typename T, typename... Ts>
auto printf3(T value, Ts... args) {
std::cout << value << std::endl;
(void) std::initializer_list<T>{([&args] {
std::cout << args << std::endl;
}(), value)...};
}

C++11引入了delegate construct,即constructor可以调用本类的其他constructor

使用using来继承父类constructor

1
2
3
4
class Subclass : public Base {
public:
using Base::Base; // inheritance constructor
};

1
2
3
4
5
struct Base {
virtual void foo() final;
};
struct SubClass1 final: Base {
}; // legal

enum class可以指定underlying type。

1
2
3
4
5
6
enum class new_enum : unsigned int {
value1,
value2,
value3 = 100,
value4 = 100
};
1
2
3
4
5
6
7
8
#include <iostream>
template<typename T>
std::ostream& operator<<(
typename std::enable_if<std::is_enum<T>::value,
std::ostream>::type& stream, const T& e)
{
return stream << static_cast<typename std::underlying_type<T>::type>(e);
}

Chapter 3

mutable声明的成员变量可以被const成员函数修改


lambda expression

1
2
3
[capture list] (parameter list) mutable(optional) exception attribute -> return type {
// function body
}

the captured variable is copied/referenced when the lambda expression is created, not when it is called

还允许expression capture

1
2
3
4
auto important = std::make_unique<int>(1);
auto add = [v1 = 1, v2 = std::move(important)](int x, int y) -> int {
return x+y+v1+(*v2);
};

类型推导与auto一致

lambda表达式没法用模板,但是C++14以后参数列表可以用auto,起到了类似模板的作用。

1
2
3
4
5
6
7
8
void lambda_generic() {
auto generic = [](auto x, auto y) {
return x+y;
};

std::cout << generic(1, 2) << std::endl;
std::cout << generic(1.1, 2.2) << std::endl;
}

std::placeholder::_1 中的 "_1": 表示新的可调用对象中的第一个参数

1
2
3
4
5
6
7
8
9
10
int foo(int a, int b, int c) {
;
}
int main() {
// bind parameter 1, 2 on function foo,
// and use std::placeholders::_1 as placeholder for the first parameter.
auto bindFoo = std::bind(foo, std::placeholders::_1, 1,2);
// when call bindFoo, we only need one param left
bindFoo(1);
}

constant references allow binding to non-lvalues

Chapter 4

vector.shrink_to_fit可以根据当前size调整capacity,而clear不会改变capacity

将std::array转化为数组指针可以通过&arr[0]或arr.data()。

std::forward_list是单向链表

std::map、std::set由红黑树实现,std::unordered_map、std::unordered_multimap、std::unordered_set、std::unordered_multiset由哈希表实现


std::tuple用于存储不同类型的数据

1
2
3
4
5
6
7
8
9
10
double gpa;
char grade;
std::string name;

// unpack tuples
auto tuple = std::make_tuple(3.8, 'A', "John");
std::tie(gpa, grade, name) = tuple;
// std::get用于从tuple中取得数据,支持index和类型(C++14),如果取的类型在tuple中不唯一则会产生运行时错误
std::string str = std::get<std::string>(tuple);
char c = std::get<1>(tuple);

std::variant<T... Ts>类似union(C++17),声明一个动态类型的变量,该变量的类型在Ts中变化,一个时间只能为一个类型,可以根据.index()得到当前使用的类型的下标。可以用std::get获取值,如果获取的非它当前的类型,会抛出异常std::bad_variant_access

利用std::variant递归可以实现非常量索引的get。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <variant>
template <size_t n, typename... T>
constexpr std::variant<T...> _tuple_index(const std::tuple<T...>& tpl, size_t i) {
if constexpr (n >= sizeof...(T))
throw std::out_of_range("越界.");
if (i == n)
return std::variant<T...>{ std::in_place_index<n>, std::get<n>(tpl) };
return _tuple_index<(n < sizeof...(T)-1 ? n+1 : 0)>(tpl, i);
}
template <typename... T>
constexpr std::variant<T...> tuple_index(const std::tuple<T...>& tpl, size_t i) {
return _tuple_index<0>(tpl, i);
}

int i = 1;
tuple_index(tuple, i);

可以使用std::tuple_cat来连接tuple

1
2
3
4
5
6
7
8
9
template <typename T>
auto tuple_len(T &tpl) {
return std::tuple_size<T>::value;
}

// 遍历
for(int i = 0; i != tuple_len(new_tuple); ++i)
// runtime indexing
tuple_index(new_tuple, i);

Chapter 5

std::shared_ptr

use_count得到reference count

reset取消该指针的reference,不影响其他指针。


std::weak_ptr has no implemented * and -> operators

the expired() method of a std::weak_ptr returns false when the resource is not released

The lock() method returns a std::shared_ptr to the original object when the resource is not released, or nullptr otherwise.

Chapter 6

std::regex

1
2
3
4
5
6
7
8
9
10
11
12
13
14
std::string fnames[] = {"foo.txt", "bar.txt", "test", "a0.txt", "AAA.txt"};
std::regex txt_regex("[a-z]+\\.txt");
std::regex_match(fname, txt_regex); // 返回值为bool
std::smatch base_match; // std::match_results<std::string::const_iterator>
if (std::regex_match(fname, base_match, txt_regex)) {
// the first element of std::smatch matches the entire string
// the second element of std::smatch matches the first expression
// with brackets
if (base_match.size() == 2) {
std::string base = base_match[1].str();
std::cout << "sub-match[0]: " << base_match[0].str() << std::endl;
std::cout << fname << " sub-match[1]: " << base << std::endl;
}
}

Modern Cpp Tutorial笔记
https://jhex-git.github.io/posts/1427194570/
作者
JointHex
发布于
2023年1月28日
许可协议