C++ typeid 语言
这是个很奇怪的的问题。但自己摸索收获了很多乐趣。
之前自己慢慢摸索研究过 typeid 语法(编译器是 g++),主要是网上似乎没有详细的教程,至少我不是很找得到。
我发现 typeid 就像一门语言,研究它的过程就像破译古代文字。
先讲一下破译工具和方法。大家可以自己尝试破译一下,乐趣多多。
-
生成文字:就按照这个模板来就行了,相信大家都看得懂:
#include<type_traits> #include<iostream> //记得添加自己想要的头文件 using namespace std; int v; //目标 signed main() { cout<<typeid(v).name()<<endl; return 0; } -
破译文字: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表示int,l表示long,n表示__int128,St表示std::,Dn表示decltype(nullptr)等等。(注,C和G我不知道归到哪一类,他们分别表示复数和虚数,这样看来更像实词。但后面都需要接类型,更像虚词。) -
实词显然数不尽,不能全用关键字。比如,
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 呢?怎么写呢?

浙公网安备 33010602011771号