贡献者: addis
详见 “C++ 字符串笔记”。
更多容器详见 “C++ 标准库常用容器”
v.size()
检查大小
v.empty()
检查是否为空
for (auto &i : v)
auto a = v.begin()
, 生成第一个元素的 iterator, v.end()
生成最后一个元素后的一个 iterator. *a
获取 a 指向的元素, *(a + n)
获取 a 后面的第 n 个元素. ==
只有在 iterator 指向同一个 vector 的同一个元素时才成立.
clock()
用于测量 CPU 时, 而不是真正的时间. 如果在 ubuntu 下用 OpenMP, 时间将是所有 CPU 的累加.
clock_t start, stop;
start = clock();
...
stop = clock();
time()
用于测量从 1970 年某时刻起流逝的秒数, 但仅限于整数秒.
若要精确测量物理时间, 用 chrono, 这个头文件用起来要复杂得多, 见我在 nr3plus.h 中写的 tic(), toc() 函数.
max()
, min()
, swap()
交换两个变量值。
int system("命令")
在调用程序的环境(如 linux 的 bash,windows 的 cmd)中执行命令,例如获得文件列表 ls
,当前目录 pwd
等。但这些命令返回的值不能直接获得,需要 redirect 到文件再读取文件。
int remove("文件名")
可以删除文件。
sizeof(variant)
会比类型列表中最大的 sizeof 稍大。
if (std::holds_alternative<int>(变量))
用于判断 variant
的类型。
std::get<int>(变量)
或者 std::get<2>(变量)
(数字表示第几个类型),可以对该 reference 赋值。型检查失败会抛出 std::bad_variant_access
。
std::get_if<int>(&v)
可以返回特定类型的指针,如果不是 int
则返回 nullptr
。
if (holds_alternative<int>(变量)) get<int>(...);
那么会检查两次类型,所以 get_if
是更好的选择,后者是 noexcept
,抛出错误也会让程序变慢。
=
赋值,>,<,==,>=
等比较算符。
#include <variant>
using namespace std;
using Operand = variant<int, double>;
Operand performOperation(const Operand& left,
const Operand& right, const string& op) {
// Visitor that applies the operation
return visit([&](auto&& arg1, auto&& arg2) -> Operand {
if (op == "+") return arg1 + arg2;
else if (op == "-") return arg1 - arg2;
else if (op == "*") return arg1 * arg2;
else if (op == "/") {
if (arg2 == 0) {
cout << "Cannot divide by zero!" << endl;
return 0;
}
return arg1 / arg2;
}
else {
cout << "Unsupported operation" << endl;
return 0;
}
}, left, right);
}
lambda
函数被调用的时候,arg1, arg2
的类型会是 variant
的具体类型。
visit
直接写 lambda 里面的东西?因为这些代码编译时,stack 中的每个变量类型和长度都是确定的,+-*/
调用的具体算法也是确定的,不可能同一个机器码在运行时用不同的类型。所以不用 visit
就必须手写 if, else
,以及手动把 variant
cast 成不同的类型。
std::visit
相当于用 if, else if
遍历 lambda 中的所有组合,并自动把变量 cast 成动态的类型。lambda 中的操作需要适用与所有组合或者使用静态类型判断,否则就会编译报错。
any
可以是任何类型,所以不可能用 std::visit
遍历,需要自己手动判断。
sizeof(any)
g++ 测试是 16 字节,但也可能更多。
any::reset()
可以清空它的值
any::operator=()
对其赋值。
any::emplace<类型>(...)
可以使用某类型的 constructor
any::has_value()
判断是否有值
if (a.type() == typeid(int))
any_cast<int>(a)
,若错误抛出 bad_any_cast
any_cast<int>(&a)
,若错误返回 nullptr
。
=
赋值,不支持比较算符。
any
的一个用处就是给一固定类型的函数指针提供用户参数。写一个微分方程解算器,用户需要提供求导函数,但如何给该函数传递参数呢(例如设置弹簧劲度系数等)?这些参数用户未必可以写死到函数中,又不想使用全局变量。一个方法是使用 functor,也就是含参对象的 operator()
,但这样就需要解算器使用模板。但万一解算器很大不值得为了一点小小的接口变化编译多个不同的版本呢?万一源码保密不能放在头文件只能编译成二进制 library 呢?除了模板,就是传递一个最后一个参数是 any
的函数的指针(没有 any
以前一般使用 void *
但这不怎么安全)。这样就可以保持函数指针类型不变,且可以传递用户想要的任何参数了。相当于用 ” 不必要 “ 的动态类型的一点性能代价让 C++ 用起来更像动态语言。虽然理论上这可以用静态方法实现,但比起编程的巨大难度(尤其是 tuple
相关的东西),损失一点可以忽略不计的性能反而是最佳方案。另一个例子是如何在 C++ 中表示数据库表中的一行?并作为参数传递给一个函数。最高性能的方法是用 tuple
,但变参数个数的 tuple
相关的编程真的很麻烦很抽象,哪怕使用模板生成都很麻烦。用 vector<variant<...>>
或者 vector<any>
会大大方便编程。详见 SLISC 的 update_sqlite_table()
的两种实现方法。