我今天发现了一段有趣的代码:
auto ch = (double(), (float(), int()))["\t\a\r\n\0"]["abcdefghij"];
Run Code Online (Sandbox Code Playgroud)
其作用相同:
char str[] = "abcdefghij";
char ch = str['\t'];
Run Code Online (Sandbox Code Playgroud)
为什么它甚至可能?特别是为什么编译器从字符串中挑选第一个char并将其用作下标而不是抛出错误?
Tyl*_*nry 12
首先,所有这些double和float东西都是纯误导.逗号运算符的返回值是它的右侧参数,因此(double(), (float(), int()))归结为just int(),尽管它在此过程中创建并丢弃a double和float值.所以考虑:
auto ch = int()["\t\a\r\n\0"]["abcdefghij"];
Run Code Online (Sandbox Code Playgroud)
将评估的第一部分是
int()["\t\a\r\n\0"]
Run Code Online (Sandbox Code Playgroud)
现在,认识到int()默认构造一个整数,它给它赋值0.所以声明等同于:
0["\t\a\r\n\0"]
Run Code Online (Sandbox Code Playgroud)
它在C和C++中是一个相当着名的技巧,a[b]并且b[a]是等效的,因为下标运算符被定义为a[b] === *(a + b)并且加法是可交换的.所以这真的是一样的:
"\t\a\r\n\0"[0]
Run Code Online (Sandbox Code Playgroud)
这当然等于'\t'.现在完整的代码是:
auto ch = '\t'["abcdefghij"];
Run Code Online (Sandbox Code Playgroud)
出于同样的原因相当于:
auto ch = "abcdefghij"['\t'];
Run Code Online (Sandbox Code Playgroud)
当然也可以写成
char str[] = "abcdefghij";
char ch = str['\t'];
Run Code Online (Sandbox Code Playgroud)
如果给了"abcdefghij"字符串一个名称,并auto在声明时使用了C++ 0x 关键字ch.
最后,注意\t等于9,因为制表符有ASCII值9,所以str['\t']它是相同的str[9].str由10个字符组成,后跟一个NUL字符终结符(\0),它隐式添加到初始化的字符串文字中.
所以在这两种情况下,最终值ch都是'j'.
我会解释为重写:
auto ch = (double(), (float(), int()))["\t\a\r\n\0"]["abcdefghij"];
Run Code Online (Sandbox Code Playgroud)
相当于(只double, float, int用逗号运算符评估所有临时值)
auto ch = (0["\t\a\r\n\0"])["abcdefghij"];
Run Code Online (Sandbox Code Playgroud)
现在标准说:
x[y] == *(x + y)
Run Code Online (Sandbox Code Playgroud)
无论哪一个是指针.所以你得到:
0["\t\a\r\n\0"] == "\t\a\r\n\0"[0] == '\t';
Run Code Online (Sandbox Code Playgroud)