《#诗盗#·颛顼死即复稣》:悠悠世道,碌碌仙术。唯寂乃明,临绝复稣。
注解
唯寂乃明:空寂顿悟,我即是佛。
临绝复稣:绝地重生。
《#诗盗#·颛顼死即复稣》:悠悠世道,碌碌仙术。唯寂乃明,临绝复稣。
唯寂乃明:空寂顿悟,我即是佛。
临绝复稣:绝地重生。
《#诗盗#·真空涨落出一个元宇宙》:稣学宇宙非学仙,恐君此说是虚传。山海不是稣归处,归即应归有顶天。
改编自唐代诗人白居易的《答客说》:
吾学空门非学仙,恐君此说是虚传。
海山不是我归处,归即应归兜率天。
多现代?C++ 11 就有了。
我想返回一个对象,但我受到惊吓……
是不是应该从指针型参数返回对象?
已经 C++20 了,请放心,直接,返回对象!
RVO:Return Value Optimization,返回值优化。
NRVO:Named RVO,具名的返回值优化。
返回的对象会 move 给接收的变量,并且,最多可能优化成直接对接收变量进行构造(NRVO)。
如果明确没有 move 构造函数,则会调用 copy 构造函数,当对象构造代价高时,应该尽量保证有 move 构造函数。
1 | // 传统,不建议,可读性差,使用也不方便 |
没有必要对返回值再加一次 std::move,因为返回本身就已经是 move,再加一次就是多一次没必要的 move。
多现代?C++ 20。
C++ 17 才有 std::string_view
,而相似的 std::span
居然到 C++ 20 才有。
如何解决 C-Style 数组(包含动态分配的连续内存)的退化(array decay)和越界访问(range errors)两大问题?
C 语言解决这两个问题,主要是增加一个长度参数。很多 Win32 API 这样做,例如:
1 | PCSTR WSAAPI inet_ntop( |
但它会带来新问题:不小心传错!另外也有一些地方并没有提供长度参数,比如下面 Linux 内核代码里的函数:
1 | static inline int ip_decrease_ttl(struct iphdr *iph); |
当我们打算把 uint8_t 数组转成 struct iphdr *
时,必须在调用前保证数组长度大于等于最小 IP 头长度。
C++ 的解决方案是:std::span
,它是一个连续对象存储的观察者。类似 std::string_view
是 std::string
的观察者。它可以同时管理数组的地址和大小,并且它没有数据所有权,仅占用最多两个指针的空间,可以像 std::string_view
一样在绝大多数时候直接按值传递。
以下函数用于获取 IP 头的长度:
1 | std::uint8_t GetHeaderLength(const void* ip_header, size_t size) noexcept; |
它可以用 std::span
包装成:
1 | template <typename T, size_t N> |
另一个便利是,使用 subspan 成员函数可以对其内部指针和长度成对操作,以避免单独处理时可能不小心少处理一个的问题。
std::span
和 std::string_view
一样,没有数据所有权,所以要担心数据失效问题,不要在数据被释放后使用。
下面是个错误示范,来自:std::string_view encourages use-after-free; the Core Guidelines Checker doesn’t complain #1038
1 |
|
多现代?C++ 17,因为本文内含 std::string_view
。
目前 C++ 20 还未普及,CLang 和 GCC 对 C++ 20 不是很上心,【直到今天 2020-08-18】连 std::format 都没有,被 MSVC 甩开。
类对象作为参数究竟应该怎么传?
《Effective C++》的条款 20 说:
- 宁以 pass-by-reference-to-const 替换 pass-by-value
为什么新规范又建议构造函数 pass-by-value?
只读访问并且不复制时,使用 pass-by-reference-to-const。
需要保存对象副本时,并且对象可移动,使用 pass-by-value。
对象很小时,使用 pass-by-value。
1 | // 只读访问,不需要将 text 保存起来。 |
Foo 的构造函数使用 pass-by-value,这使得它变成“两用”的,相当于针对这个类对象参数同时实现复制构造函数(ctor)、 移动构造函数(mtor)。
当传一个左值给它时,参数 message 是复制的,但它立刻移动给了成员变量 message_,整个过程发生一次复制和一次移动;
当传一个右值给它时,参数 message 是这个右值移动而来的,然后又立刻移动给了成员变量 message_,整个过程发生两次移动;
1 | std::string name("UMU618"); |
如果类实现得妥当,移动两次对象实际上最多可以被编译器优化成零次。
由于没有经费写《后传》就把后传的内容写到《番外篇》了。
周易是老钧的化身之一。他看到任何结局,但都不去干预。莫名其妙?没错,这正是他的特征。
圣仙山就会去干预世事演化,而成为天道的执行者之一,本质是个工具人。
大部分英雄电影都有一些角色会因为法律、信仰、道义、情感等原因去干预世事,尤其一些穿越剧,妄想改变历史。这些都是不符合天道的。
天地不仁,以万物为刍狗。所以周易最厉害。
当然是。
首先要认识到人类集体显意识是确实存在的,比如中药学就是靠着集体显意识保存下来的。如果某种技能只有一个人会,那么它失传是必然的,这个人一死就失传了。存在集体显意识里就不容易失传,但集体显意识也不一定能够很客观地保存信息,有些人出于某种目的,会篡改信息。并且不是什么信息都可以靠集体显意识保存,比如有些东西无法达成共识。
举个例子,噬菌体,一种可以编程控制的半生命体,可以编程它来定向消灭细菌,比如治疗青春痘……安全有效不含抗生素。它在古代治疗过很多奇怪的疾病,尤其是被下蛊之类的,那时候医学理论不完善,人们便以为是草药起了作用,其实是自然界中的噬菌体治好的。这个事情在集体显意识里是没有记录的,它只在集体潜意识里保存。
PS:1990 年以来,人类几乎没有发现新的抗生素种类了。世界卫生组织 2017 年 9 月份宣布,“确认世界的抗生素频临枯竭”。参考:https://www.who.int/zh/news/item/20-09-2017-the-world-is-running-out-of-antibiotics-who-report-confirms
总之抗生素要完,以后由细菌导致的疾病只能靠噬菌体了。
其次,如果承认个人是有潜意识的,那么集体也应该有集体潜意识。
稣的由来可以有很多解释,但根源来自圣仙山参与写作的《山海经》。
我们注意到现实中的颛顼在八哥宇宙里名字是:姬稣。
作者为什么选择和颛顼攀关系呢?其实颛顼和《八哥之神》的主题十分契合。不信您翻开圣仙山参与写作的《山海经》,里面有一句话特地被重复两次。
有鱼偏枯,名曰鱼妇。颛顼死即复苏。风道北来,天及大水泉,蛇乃化为鱼,是为鱼妇。颛顼死即复苏。
古人惜墨如金,为什么这句话非要写两遍?这里面藏着惊天大秘密!——意识是可以重复的,唯一可以穿越时间的,也只有意识。比如现代人死后可以回到古代,但由于记忆无法穿越,所以不会存在任何时间悖论。
“稣”字和“苏”同音,并且就是“鱼”字旁,对应文中多次提到的“鱼”。当圣小开要自称稣时,显然“稣”更合适,因为“苏”是个姓,容易被人误会姓苏。
确切地说,圣仙山以巫咸的身份写了《山海经》的预言部分,而这部分正好因为威力太大,若为坏人得之,天下危矣,故被大禹删除。
也有另一种说法是,巫咸给《山海经》作序用的是大禹看不懂的文字(Bân-lâm-gú),所以到这部分预言内容就慢慢失传了。
幸运的是,识界里还保留着完整的《山海经》,刚好作者就懂 Bân-lâm-gú,所以才能得知这些故事,写出《八哥之神》。不过由于《八哥之神创世手稿》失传,导致并非人人可以通过修炼它而进入识界,天下得以承平日久。
PS:圣仙山和妹妹李灵海,名字合起来就是“山海”,这也是个暗示,历史上的巫阳就是李灵海的前世,秦阳也和巫阳相对应,他们都是同一个意识在不同时期或者境界的具化体。
是的!姬稣是坚定的无神论,所以有“绝地天通”,破除迷信,不让觋巫扰乱民间。在怪力乱神的时代,姬稣实乃是无神论里少数善终之人,活了 97 岁。
另一个无神论者就很惨,他就是齐凤卿前世帝辛,实则是位明君,但由于是无神论者,得罪势力集团,被污蔑造谣为暴君,至今难以平反。em……不能因为妲己长得漂亮,就说她是狐狸精吧!这太不科学哩!
暂时扯到这里。
本文可简单了……结论先行:尽量别用 Boost 进行函数式编程。
Boost | STL | Header |
---|---|---|
Boost.Function | std::function | <functional> |
Boost.Bind | std::bind | <functional> |
Boost.Ref | std::ref, std::cref | <functional> |
Boost.Lambda | lambda | part of C++11 |
有时候用 Boost.Phoenix 省事,因为它就像 lambda 表达式的模板,比如:
1 |
|
本例中采用 Boost.Phoenix 可以自动适配 int 和 long long,而 lambda 表达式是确定的 int 参数,传入 long long 会 warning。
C++14 支持基于类型推断的泛型 lambda 表达式,将上面代码改进一下,说明没必要使用 Boost.Phoenix:
1 |
|
STL 和 Boost 都有的类应该用哪个?
如果是标准库原本没有,Boost 先有,然后 Boost 的实现被加入标准库,那么应该使用标准库。
如果 Boost 加强了标准库的实现,那么就看标准库能不能满足您的需求,如果不能再采用 Boost 的。
因为依赖而必须采用 Boost,那就别费力去改用标准库。比如有些 Boost 库(比如 Boost.Log)使用了 boost::shared_ptr,这时候是不能简单地改用 std::shared_ptr 的。
本文代码:https://github.com/UMU618/test_boost
使用 std::cout 指定进制打印数字时经常有一个烦恼:之前设置的进制会一直有效,比如临时想打印一个 16 进制数,然后都打印 10 进制,这时候需要 std::hex,打印,再 std::dec,如果忘记 std::dec,那么后面的数字就全是输出 16 进制形态了……而且,您怎么知道之前用的就是 std::dec?万一是 std::oct 呢?
使用 boost::io::ios_all_saver 自动保存和还原 ios 状态。
1 |
|
打印数组时,不想最后一个元素后面跟着一个分隔符。因为这会让完美主义纠结症患者抓狂!
C 语言奇葩版,连 if 都不需要:
1 |
|
上面的方案纯属炫技,还是用 ostream_joiner 来搞定,一样看不到 if:
1 |
|
大部分语言的字符串都是需要转义的,除非用原始字符串(raw string),有时候想打印出转移后的字符串。
使用 C++14 的 std::quoted,或者 boost::io::quoted,默认参数就是 C/C++ 的转义风格。
1 |
|
其它系统请参考:
Windows:《Boost【1】安装》
macOS arm64
XCode
1 | brew install p7zip |
macOS 的 brew 更进 boost 很积极,现在就是最新版 1.76:
1 | # install b2 and boost |
然后跳到文末的“测试安装”。
1 | cd ~/Downloads |
1 | 7z x boost_1_76_0.7z |
1 | cd boost_1_76_0 |
1 | b2 install |
可以用以下仓库验证前面操作是否正确:
https://github.com/UMU618/test_boost
1 | git clone https://github.com/UMU618/test_boost |
最终编译出来的程序应该打印“OK!”。
在《Boost【1】安装》中以 Windows 为例介绍 Boost 的安装,最近主要在 Linux 上开发,发现差异还是比较大的,于是又有了本文。
Debian Buster/Bullseye
clang-11/gcc-10
1 | apt install wget -y |
如果您怕麻烦,而且不在乎使用最新版本 Boost,还可以直接用 apt 安装 1.74 的版本:
1 | # install b2 |
然后跳到文末的“测试安装”。
1 | cd ~ |
1 | # 7z x boost_1_76_0.7z |
1 | # use /usr to avoid setting PATH |
1 | # b2 install --build-type=complete --layout=versioned --prefix=$INSTALL_DIR --exec-prefix=$INSTALL_DIR |
1 | mkdir ~/boost-3-installation-on-linux |