奇怪的东西
Lambda表达式
其实就是C/C++
函数的另一种定义方式
1 2 3 4 5 6 7 8 9 10 11 12
| function<void(int)> dfs = [&](int u) { if(tree[u].l) dfs(tree[u].l); if(tree[u].r) dfs(tree[u].r);
for(int i = 1; i <= m; ++i) { dp[u][i] = (dp[tree[u].l][i - 1] * dp[tree[u].r][i]) % mod; dp[u][i] = (dp[u][i] + dp[u][i - 1]) % mod; } };
|
1 2 3 4 5 6 7 8 9 10 11
| void dfs(int u) { if (tree[u].l) dfs(tree[u].l); if (tree[u].r) dfs(tree[u].r);
for (int i = 1; i <= m; ++i) { dp[u][i] = (dp[tree[u].l][i - 1] * dp[tree[u].r][i]) % mod; dp[u][i] = (dp[u][i] + dp[u][i - 1]) % mod; } }
|
function<void(int)>
:一个 C++ 标准库中的 std::function
类型,表示一个可以接受一个 int
参数并返回 void
的可调用对象。
[&]
:捕获列表.表示 lambda 表达式可以通过引用捕获周围作用域中的所有变量。使得你可以在 lambda
内部访问外部的变量.
1 2 3 4 5 6 7 8 9 10 11 12 13
| auto dfs = [&](this auto&& self, int u) -> void { if(tree[u].l) self(tree[u].l); if(tree[u].r) self(tree[u].r);
for(int i = 1; i <= m; ++i) { dp[u][i] = (dp[tree[u].l][i - 1] * dp[tree[u].r][i]) % mod; dp[u][i] = (dp[u][i] + dp[u][i - 1]) % mod; } };
dfs(root_node);
|
stringstream
stringstream
是 C++ 标准库中位于 <sstream>
头文件内的一个类,主要用作字符串的流式处理。它可以像流一样操作字符串,用来将不同类型的数据插入到字符串中或从字符串中提取数据,方便类型转换和字符串拼接。(豪丸)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
string str; stringstream ss(str);
string input = "123 3.14 hello"; stringstream ss(input); int num; double pi; string text;
string s; getline(cin, s); ss << s; while(ss >> s) do something;
ss >> num >> pi >> text;
ss.str("") ss.clear();
|
bitset
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| std::bitset<8> b1; std::bitset<8> b2(42); std::bitset<8> b3("10101010");
b1.set(3); b1.set(); b1.reset(); b1.reset(2); b1.flip(); b1.flip(1);
std::cout << b2.count(); std::cout << b2.any(); std::cout << b2.none(); std::cout << b2.size();
std::cout << b2.to_string() << std::endl; std::cout << b2.to_ulong() << std::endl;
|
类型转换
static_cast
,dynamic_cast
,const_cast
,reinterpret_cast
。
C++ 中用于进行显式的类型转换的关键字,每个操作符有不同的用途和适用场景。比 C 风格的强制转换更具类型安全性,可读性。
static_cast
用于普通的类型转换,适用于已知类型之间的转换。
1 2
| double d = 3.14; int i = static_cast<int>(d);
|
dynamic_cast
用于处理类层次结构中的类型转换
1 2 3 4 5 6 7 8 9 10 11 12
| class Base { public: virtual void foo() {} };
class Derived : public Base {};
Base* base = new Derived; Derived* derived = dynamic_cast<Derived*>(base); if (derived) { std::cout << "Conversion successful" << std::endl; }
|
const_cast
用于去除或添加 const
限定符。
1 2 3
| const int x = 10; int* ptr = const_cast<int*>(&x); *ptr = 20;
|
reinterpret_cast
用于进行低级别的指针或引用转换,允许你在不进行任何检查的情况下将一种类型转换为另一种完全不相关的类型。这种转换是最强大和最危险的。
1 2
| int a = 10; char* p = reinterpret_cast<char*>(&a);
|
奇怪的返回值类型
.size()
STL的容器的.size()
函数的返回值类型是size_t
,他是一个无符号整数,位数却决于你的机器架构。int
和size_t
进行运算的时候,默认是将int
转为size_t
,这可能引起问题,需要我们自己进行类型转换。
it - numbers.begin()
两个迭代器的差,返回值类型是difference_type
,通常被定义为 ptrdiff_t
类型,是一个有符号整数。ptrdiff_t
用于表示指针之间的差值,在 C++ 中常用于表示迭代器之间的差值,ptrdiff_t
的大小与机器架构相关。
emplace
emplace
是push_back
和insert
的上位替代,使用 emplace
时,直接在容器内部构造对象,避免了额外的拷贝或移动操作,而使用 insert
和push_back
时,通常需要先创建一个临时对象,然后再将其插入容器。
emplace
的返回值是std::pair
,其中first
是一个迭代器,指向插入的元素,second
是bool
,表示插入是否成功(对于自动去重的容器,元素已存在,则插入失败)。
因为上面说的特性,存在如下情况。
1 2 3 4
| set<pair<int, int>> st; st.insert({1, 1}); st.emplace({1, 1}); st.emplace(1, 1);
|
函数对象
函数对象(也称为 仿函数,Functor)是 C++ 中行为像函数的对象。它通过重载 operator()
来实现函数调用,使得对象可以像函数一样被调用。
1 2 3 4 5 6 7 8 9 10 11
| struct Adder { int operator()(int a, int b) const { return a + b; } };
int main() { Adder add; int result = add(3, 5); cout << result << endl; }
|
hash<int>{}
是 C++ 标准库提供的哈希函数对象,用于计算 int
类型的哈希值。它是 std::hash
模板的一个特化版本。
1 2 3 4 5 6 7 8
| #include <functional> #include <iostream>
int main() { std::hash<int> hasher; size_t hash_value = hasher(42); std::cout << hash_value << std::endl; }
|
Lambda 表达式的底层也是函数对象。
顺便讲一下这个位置的const
的作用,有两个:
- 保证这个函数不会修改成员变量
- 觉得对象能否调用这个成员函数,具体如下:
const
成员函数:const
对象和非 const
对象都能调用。
- 非
const
成员函数:只有非 const
对象都能调用。
一个应用:自定义哈希函数(一些奇怪的数据类型没有默认哈希函数,作为map的键时会报错,此时需要自定义)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include <unordered_map> #include <functional> #include <string>
struct Person { std::string name; int age; };
struct PersonHash { std::size_t operator()(const Person& p) const { return std::hash<std::string>{}(p.name) ^ std::hash<int>{}(p.age); } };
int main() { std::unordered_map<Person, int, PersonHash> person_map; person_map[{"Alice", 30}] = 100; }
|