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
呢?怎么写呢?