C++ typeid 语言

这是个很奇怪的的问题。但自己摸索收获了很多乐趣。

之前自己慢慢摸索研究过 typeid 语法(编译器是 g++),主要是网上似乎没有详细的教程,至少我不是很找得到。

我发现 typeid 就像一门语言,研究它的过程就像破译古代文字。

先讲一下破译工具和方法。大家可以自己尝试破译一下,乐趣多多。

  1. 生成文字:就按照这个模板来就行了,相信大家都看得懂:

    #include<type_traits>
    #include<iostream>
    //记得添加自己想要的头文件
    using namespace std;
    
    int v; //目标
    
    signed main() {
    	cout<<typeid(v).name()<<endl;
    	return 0;
    }
    
  2. 破译文字:Windows 下请下载 MSYS,Linux 和 Mac 自带。打开命令行,输入:c++filt -t 回车后,进入解码模式。输入想要的内容回车即可。

    你可以输入 St6vectorIiSaIiEE 来验证是否成功,答案是 std::vector<int, std::allocator<int> >。退出这个解码界面,ctrl+C 就可以了。

你可以先不看下面的,先自己摸索一下:为什么会这样转换?原理是什么?加入给你一个 typeid 文字,你能否自己读懂是什么意思?能否自己写出一段 typeid 文字?


下面我用语文中的实词、虚词和语法来类比。

以下是我发现的几个比较重要的点(下面的东西的中文名字都是我自己编的,感性理解一下):

  • i,l,c,x,n,St,So,Si,Ci,Gi,Dn 等等都是特殊实词关键字,属于实词。比如 i 表示 intl 表示 longn 表示 __int128St 表示 std::Dn 表示 decltype(nullptr) 等等。(注,CG 我不知道归到哪一类,他们分别表示复数和虚数,这样看来更像实词。但后面都需要接类型,更像虚词。)

  • 实词显然数不尽,不能全用关键字。比如,std::vector = St6vectorIiSaIiEE。可以看出,由于我们不确定名词的长度,所以在这之前要加上长度,比如 6vector

  • 虚词我掌握的比较少,显然虚词都是关键字。目前了解的有 F - 函数,E - 某段话结束,I - 模板参数列表开始,P - 指针前缀(对应 type*),K - 常量前缀(对应 const),V - 禁止优化前缀(对应 volatile),R - 引用前缀(对应 type&),O - 未知语法用途(对应 type&&)。

    已知但没有破译的有:N,M,Z,S,_,U(Ul?)。比较清楚的是 S_ 关键字似乎是省略语法,但不清楚怎么用。

    • 其中 N,M,Ul 可以在全局空间开一个 lambda 来复现,譬如 auto f=[](int i)->int{return i;}; ,然后查看 f 的类型。
    • N 可能表示 namespace。
    • Z 可以用类似的方法,在局部开一个 lambda 来复现。
    • S_ 也可以通过函数复现,比如 int f(vector<int> x,vector<char> c,vector<int> cc) {return 1;} ,查看 f 类型可以发现,它用 S_ 语法省略了 St6vector,甚至 St6vectorIiSaIiEE
  • 虚词有对应的语法。

    • 一个很常用的语法是列表语法。用 实词+实词+...+实词+E 表示。比如模板参数列表:IiiiiiiE 表示 <int,int,int,int,int,int>。因为有 E 的存在,显然我们不需要列出参数个数。
    • 结合列表语法,可以得到函数语法:F+形参实词+实参实词+...+实参实词+E,即一个形参加若干个实参构成,和函数对应,可以还原成函数。
    • 一个可能的语法是省略语法,类似平时说话时,前面提到的人名不造成歧义的情况下后面通常省略。即上文的 S_ 语法。

有发现就有未知。除了以上提到的,现在最成谜的类型/语法是它:lambda 表达式!譬如auto v=[](int i)->int{return i;}; 可以导出 N1vMUliE_E。而通过 c++filt 转化,又得到 v::{lambda(int)#1}。我实在没猜出来 lambda 表达式转换回去的那个 #1 等等是什么意思。另外,又能不能写成 #2 呢?怎么写呢?

posted @ 2023-06-18 21:26  robinyqc  阅读(96)  评论(0编辑  收藏  举报