lil_tea c++ 2026 style guide 总结一句话: 坚持 c like 特色指针主义道路, 以安全性换自由; 姓 bjarne 还是姓 graydon 的问题上我们要坚持 bjarne 领导, 坚持 kr 的文化自信, 坚决杜绝 graydon 的糖衣炮弹.think twice, code once. enjoy~调试最重要的当然是打印函数:void log(long line_num) {#ifdef lil_teastd::println(std::cerr, line: {} | hey siri, play hitem up please, line_num);#endif}但是向量加法函数可以有新的办法了:std::vectorlong add(const std::vectorlong a, const std::vectorlong b)pre(a.size() b.size()) { // c 2026 新特性, 见 [contracts](https://en.cppreference.com/w/cpp/language/contracts.html)std::vectorlong c(a.size());for (long x : std::views::iota(0, c.size()))c[x] a[x] b[x];return c;}用 contracts 配合g-16 -fcontract-evaluation-semanticquick_enforce就又可以让代码 fail fast 了.代码框架标识符全部使用 snake_case, 和 STL 保持统一, STL 用 snake_case 那我也用.这方面我和 bjarne 的意见相同, 可以在 bjarne stroustrup qa2 的how do you name variables? do you recommend hungarian?条目见到 bjarne 观点的详细陈述.头文件用#include bits/stdc.h, 或者直接用import std.不是说这个代码是竞赛专用, 只要 g 提供了就说明这个头文件是有意义的, 开发中使用也有很多好处, 增加的编译时间可以忽略不计.有人说这个会引入一些符号, 这个要分两方面说:函数名容易冲突. 你不using namespace std哪来的函数名冲突?宏名容易冲突. 首先你应该少定义宏, 其次我不知道你为什么非要定义一个冲突的宏名, 再说了这里面定义的什么宏是你需要再定义一遍的?而且我用这个头文件有个次要目的是为了避免我的代码被 msvc 编译, 因为我只能确定我的代码在类 unix 系统上不出错, windows 上出任何错误都有可能.命名空间禁止using namespace std;.推荐的有using namespace std::literals;.宏一般不要在代码里用宏.这方面我和 bjarne 的意见再次相同, 可以在 bjarne stroustrup fq2 的so, whats wrong with using macros?条目见到 bjarne 观点的详细陈述.例外情况是, 假如你叫李华, 你可以定义-Dli_hua表示你在 debug, 然后写:void log(long line_num) {#ifdef li_huastd::println(std::cerr, line: {} | im not good at English, line_num);#endif}常量用k_前缀来代表这是个常量, 能用constexpr尽量用, 否则用const.比如说:constexpr long k_inf 0x3f3f3f3f3f3f3f3fl; // 用于最大值, 最小值直接用 -k_infconstexpr long k_mod 998244353; // 用于取模constexpr long k_max_vtx 1l 17; // 用于顶点数量, 2^17 10^5变量尽量缩小变量的作用域, 比如for用的变量就尽量不要让作用域到for外面.引用符号和指针符号紧贴变量, 如tree *ld_或const std::vectorlong a.在类型明确的时候可以用auto, 需要明确类型的时候用类型名.这个明确包括函数返回值的类型, 认为是明确的.auto tuple std::make_tuple(1, 2, 3);auto x std::move(y);for (std::size_t x : std::views::iota(0uz, v.size()))std::println({}, v[x]);当然带权图遍历连边应该用结构化绑定:for (auto [y, z] : x-to_)y-dfs();如果要修改 (比如标记一条边) 就用引用:for (auto [y, z, delta] : x-to_)if (y-dfs())delta 1;全局变量如果可能会被多个线程修改就加锁, 如果确定只会被单线程修改就不用加锁.用namespace管理全局变量和对应的锁.namespace total { // 实际变量名long val; // 占位变量名std::mutex lock;}全局变量名不加g_前缀, 查询或修改全局变量的函数名需要加g_前缀.函数大多数函数的返回值应该只跟参数有关, 一个函数只做好一件事, 尽量不动全局变量, 动全局变量的函数的函数名需要加g_前缀.如果一个参数不变, 一定要加const. 比如刚才那个向量加法函数.如果两个参数指向的内容不会重叠, 一定要加restrict. 优化的作用对我来说并不重要因我我信任-O2, 但这样可以提醒我多次检查不要传入重叠的东西.合理情况下可以用运算符重载.引用符号和指针符号紧贴变量, 如果有restrict则写类似long *restrict a, long *restrict b.匿名函数只能用于回调函数, 比如:// std::vectorlong astd::sort(a.begin(), a.end(), [](long x, long y) {return y x;});很明显这个例子并不好, 完全可以用std::sort(a.rbegin(), a.rend())一行搞定的事非要用匿名函数, 但这是为了演示匿名函数所以情有可原, 实际应用中最好是使用std::sort(a.rbegin(), a.rend()).main函数用signed main, 可以是signed main(int argc, char **argv)也可以是signed main(void), 根据需求来.没有出错则return 0, 否则return 1.类无论是单纯存数据还是带有函数, 都用class.类变量变量名后加下划线, 比如ld_tot_.根据需要可以放private或public, 不必全放在private. 最好的例子是我用于处理图的类:class vtx {public:std::vectorvtx* to_;long dfn_, low_; // for tarjanvtx *top_, *dear_mama_, *kid_; // for 树链剖分void add_edge(vtx*);void dfs_tarjan(/*anything*/);void dfs1_hld(vtx*), dfs2_hld(vtx*);};vtx v[k_max_vtx];类函数根据需要可以放private或public, 不必全放在public, 最好的例子是线段树:class tree {std::unique_ptrtree ld_, rd_;long left_, right_;long val_, tag_;void push_up(void); // 私有void push_down(void); // 私有public:tree(long, long, const std::vectorlong); // 公有void update(long, long, long); // 公有long query(long, long, long); // 公有};构造函数非常推荐, 一定要用初始化列表. STL 容器可以初始化或不初始化. 智能指针见后文指针部分.tree(long left, long right, const std::vectorlong a): left_(left), right_(right),val_(0), tag_(0) {if (left_ right_) {val_ a[left_];return;}ld_ std::make_uniquetree(left_, left_ right_ 1, a);rd_ std::make_uniquetree((left_ right_ 1) 1, right_, a);push_up();}构造函数里为类变量区分复制,引用,抢劫复制是说你要给传入的 object 复制一份, 也就是ld_ new tree(*y-ld_).引用是说你要引用传入的 object, 也就是ld_ y-ld_.抢劫则很明显就是你要让传入的 object 失效, 也就是ld_ y-ld_, 注意一定要额外写一行y-ld_ nullptr, 或者直接写ld_ std::move(y-ld_).析构函数非必要不写, 让智能指针和 STL 自动释放, 如果有裸指针则在析构函数里以合理方式杀死.重载运算符非常推荐, 比如矩阵乘法, 重载运算符后可以方便的实现矩阵快速幂.shared_from_this千万不要用shared_from_this, 使用传入的std::shared_ptr 或const std::shared_ptr 代替.参数名建议叫ref_this, 先判断:if (ref_this.get() ! this)std::terminate();当然这里现在用pre会更方便了.std::weak_ptr的重载版本比如说有classx::work(std::shared_ptrclassx ref_this), 这时候我还会写一个重载的classx::work(std::weak_ptrclassx ref_this).内容很简单, 直接调用: