0%

"python" "%~dp0%~nx0"
exit

"""
字符串对于 cmd 来说是外部命令或参数,对于 python 来说是可拼接的字面量。
exit 对 cmd 来说是退出,对于 python 来说是一个函数名。
exit 会中止调用者,但在桌面点击运行的环境下可以正常使用。
"""

import uuid
import subprocess

def main():
    while (input('Hit enter to generate another key: ').strip() == ''):
        s = str(uuid.uuid4())
        subprocess.run("clip", text=True, input=s)
        print(f'{s} is sent to your clipboard!\n')

if __name__ == '__main__':
    try:
        main()
    except:
        pass
    input('\nYou entered something else. Program will end after your next input.')

列表构造顺序

libstdc++ 用的是递归反向构造,尾部的参数先构造。与之对应,libc++ 用的是 parameter pack 继承,是正向构造。

下标编号

两者都使用了下标编号。这样即便 std::tuple 的某两个参数类型相同,也能通过不同的下标把两个元素区分开。

EBCO

两者都有 EBCO 技术。假定 Base<T, bool = InheritableEmptyBase<T>::value> 为两个库所用的元素包装类,Base 在参数为空类且能够被继承时,采用继承的方式存储元素,否则用成员变量存储元素。

但是由于元组参数构造顺序不同,两种库实现占用的空间也可能不同。考虑类型 std::tuple<A, char, A, char, B>,其中 AB 都是空类型,它在 libc++ 中只需要占用 2 个字节。

而 libstdc++ 中同样的类型需要占用 3 个字节:

涉及的 libstdc++ 源码文件:bits/std_function.h

印象: std::function 做了小对象优化,同时在避免使用虚函数(尽管它可以用继承和虚函数来实现)。

关于成员指针,见 Pointer to Member

存储结构

首先看 std::function 的成员组成:

void swap(function& __x) noexcept
{
    std::swap(_M_functor, __x._M_functor);
    std::swap(_M_manager, __x._M_manager);
    std::swap(_M_invoker, __x._M_invoker);
} // 模板太长了,成员定义很分散,抄起来很累;这个 swap 函数写的刚刚好

相关文件:

  • include/set 头文件按顺序引入了 include/bits/stl_tree.hinclude/bits/stl_set.h
  • include/bits/stl_set.h 定义了 std::set,依赖了 include/bits/stl_tree.h 却没有明确包含它。
  • include/bits/stl_tree.h 定义了诸多类型,如未明确指出则默认下面提到的类型都是来自于这个头文件
  • src/c++98/tree.cc 实现了红黑树用到的非模板算法。这个文件只有 400 多行。

std::set 将实现转发给 _Rb_tree 处理,而它又将实现转发给了 _Rb_tree_impl 处理。

_Rb_tree_impl 继承于:

  • _Node_allocator:是一个 typedef,实际类型是一个模板类,模板参数和 _Rb_tree 的参数有关。
  • _Rb_tree_key_compare:是一个模板类,模板参数和 _Rb_tree 有关。
  • _Rb_tree_header非模板类。包含了 _Rb_tree_node_base 结构和 _Rb_tree_node_count。前者是表示红黑树结点的聚合类,包含了 parent/left/right/color 四个重要成员;后者是结点计数。初始化时,parent/left/right 都被设置为 header 本身的地址,而 color 被设置为红色,可见这个 header 就是标准库红黑树中的 nil 哨兵。另外,left 和 right 还有最小结点和最大结点的含义。

Abominable Function Types (open-std.org) 中:

For the purposes of this paper, an abominable function type is the type produced by writing a function type followed by a cv-ref qualifier. Example: using regular = void(); using abominable = void() const volatile &&;

通过一些模板手段能把类中的成员函数转换成可憎函数(怎么翻译更合适?)。可憎函数形式复杂,模板匹配困难。C++23 explicit object parameter (deducing this) 可以一定程度上解决这个问题。

这个东西现在看来不该存在,是 this 指针设计的历史遗留问题。

例子:

#include <iostream>
#include <numeric>
#include <vector>

int main() {
    std::vector v{1, 3, 5}; // 模板类参数推导:T=int
    std::cout << std::accumulate(begin(v), end(v), 0);
    //        ^^                  ^^        ^^ 都是ADL
}

使用 beginendswap 等函数模板时,先引入其名字到当前空间中,然后再调用,有助于 ADL 查找到性能更优的函数实现:

{
    using std::swap;
    swap(A, B); // 假设 A 和 B 是已经定义的同类型变量
}

博文 Should I use the two-step in non-generic code? 认为在非泛型代码中不必使用 using std::swap,直接使用 x.swap(y) 或者 std::swap(如果是内置类型或者 std 名字空间中的类型)即可。

注意,有 bit fields 或者 有成员默认值 或者 有匿名 union 成员 也可以是 aggregate。

对含有 union 成员的聚合类使用 花括号默认的全参数构造函数 初始化时,初始化的是 union 的第一个元素(不管 union 是不是匿名的)。

(C++20) 隐式提供的的全参数构造函数

#include <iostream>
#include <vector>

struct Point {
    double x;
    double y;
};

int main() {
    std::vector<Point> points;
    // 可以省略类型,花括号自动推导。
    points.push_back({1, 1});
    // 必须要写Point类型。因为是模板参数,捕获的时候不知道目的类型,不能推导。
    points.emplace_back(Point{1, 1});
    // 下面两行在 C++20 可以编译:
    points.emplace_back(1, 2);
    auto some_point = Point(1, 2);
}

注意这样的全参数构造函数是具有 explicit 属性的。所以下面的代码不能编译:

用于标注函数返回值

令人意外的是:C++14 加入的返回值推导是一种特殊的类型,和前向声明并不兼容。

int known();
auto known() { return 42; } // 错误:类型不兼容
// int known() { return 42; }         // ok
// auto known() -> int { return 42; } // ok

同样:

auto known();
int known() { return 42; } // 错误:类型不兼容
// auto known() { return 42; } // ok

C++ 14 还加入了 decltype(auto),这个组合不像单独的 auto,不能被 const 等继续修饰。

bash 的两个配置文件

login 时只加载 .bash_profile(如果存在),其他时候只加载 .bashrc

最好是把内容放在 .bashrc,然后让 ~/.bash_profile 去 source ~/.bashrc

虽然 ~/.bashrc 是所有非登陆的 bash 都会读,但默认的 ~/.bashrc 的开头检查了当前是否为交互终端,如果不是则退出。如果非要绕过这个限制,可以强制一个终端为交互终端:bash -i

Windows 的 Cygwin 目录下自己有 home。因此要让它的 ~/.bashrc 去 source Windows 用户目录的 ~/.bashrc,不然会出现两处配置不一致的情况。

bash 显示 git 分支

parse_git_branch() {
    if ! [[ $(git rev-parse --is-bare-repository 2>/dev/null) == true ]]; then
        local BRANCH="$(git branch 2>/dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')"
        [[ "${BRANCH}" == "" ]] && return 0
        local MSG="$(git status 2> /dev/null | tail -n1)"
        if [[ "$MSG" != "nothing to commit"* ]]; then
            echo -n "(${BRANCH}*) "
        else
            echo -n "(${BRANCH}) "
        fi
    fi
}
EXITCODE='$(code=$?; if (( code )); then echo -ne "\[\e[91m\][$code]\[\e[00m\] "; fi)'
export PS1="${EXITCODE}\u \[\e[32m\]\w \[\e[00m\]\[\e[91m\]\$(parse_git_branch)\[\e[00m\]$ "