c++中奇怪的解析:int f(int(arg))等价于int f(int arg)——有人能解释一下吗?

Weird parse in C++: int f(int(arg)) equivalent to int f(int arg) - can anyone explain it?

本文关键字:int arg 能解释 一下 c++ 等价于      更新时间:2023-10-16

这是我的一个同事在试图构造一个只有一个参数的对象时发现的:

char testString[] = "test string";
...
MyClass instance(QString(testString));

他们意识到这样一种情况:如果你用函数风格的习惯用法构造一个单参数,它将被解析为一个前声明的函数,例如

char test[] = "hello";
MyClass instance1(0, test) //constructs an object
MyClass instance2(test) //invalidly forward-declares a function

但是他们被他们认为应该工作的东西难住了,因为它在括号内包含了函数风格的强制转换,或者单参数构造函数调用。

我已经发现他们的构造函数调用被解析为:

MyClass instance(QString testString);

没有将变量testString传递给强制转换操作符,而是声明了一个带有同名形参的函数。我的问题是,为什么会这样?它似乎允许参数名被括号包围

这是我的一个同事发现的

不,它是几十年前"发现"的,是语言中一个非常著名的怪癖。

  • https://en.wikipedia.org/wiki/Most_vexing_parse

我的问题是,为什么会这样?它似乎允许参数名被括号括起来。

。C声明语法没有规定不允许这种特殊情况。在一般情况下,它对于像这样的更复杂的结构很有用:

void foo(int (*func)(char));
// (takes a pointer to a function returning int and taking char, bool)
// as opposed to:
void foo(int *func(char));
// (takes a function returning int* and taking char)
// as this is literally equivalent to the clearer:
void foo(int* func(char));

, c++中:

void foo(int (&array)[5]) {}
// (takes a reference to an array of five integers)
// as opposed to:
void foo(int &array[5]) {}
// (takes an array of five `int&`s ... and fails to compile accordingly)

对于您的具体情况,这是公认的笨拙的解决方案:

MyClass instance((QString(testString)));
//               ^                   ^

或者,自c++ 11以来更有用的:

MyClass instance(QString{testString});
//                      ^          ^

这实际上是引入统一初始化语法的驱动因素之一。


附录

如果你用函数风格的习惯用法构造一个参数,它将被解析为一个前向声明的函数,例如

MyClass instance2("hello") //invalidly forward-declares a function

这种说法根本不正确。

另外,char *testString = "test string";已经被弃用了17年,非法使用了4年。

在c++和C语言中,声明符可以用任意数量的圆括号括起来:

int a;
int (b);
int ((c));
int f(int (x));

这主要用于区分函数指针声明符和返回指针类型的函数声明符。例如,这里的f是指向一个函数的指针,该函数接受一个int并返回一个int:

int (*f)(int x);

换句话说,如果xint,则(*f)(x)int。而在这里,f是一个接受int并返回指向int的指针的函数:

int *f(int x);

也就是说,如果xint,那么*f(x)就是int