最令人烦恼的解析与阵列访问

Vit*_*meo 21 c++ most-vexing-parse c++03

在查看一些C++ 03代码时,我发现了一个让我感到困惑的最令人烦恼的解析实例:

#include <sstream>
#include <string>

int main(int, char** argv)
{
    std::stringstream ss(std::string(argv[0]));
}
Run Code Online (Sandbox Code Playgroud)

wandbox上的实例

在上面的代码片段中,ss是一个函数的声明,它接受std::string*并返回std::stringstream.

怎么std::string(argv[0])解析为std::string*

直觉上,我认为这argv[0]是明确无误的访问argv.

Jod*_*cus 18

原因是因为在函数声明的上下文中,编译器将解释std::string(argv[0])std::string argv[0],即一个零大小数组的声明作为命名 的函数参数argv(遮蔽了argvfrom main,因为这是一个不同的范围),这相当于由一个指针阵列到指针衰变.

因此,std::stringstream ss(std::string(argv[0]));意思相同std::stringstream ss(std::string* argv);

编辑:由于它在注释中被正确注释,零大小的数组声明在C++中无效,导致程序格式错误.使用-pedantic标志(GCC和clang)编译此代码时,将发出警告.Visual Studio甚至会产生编译错误.对于除0以外的任何其他数组索引,上述论证仍然成立.

  • 所以最令人烦恼的解析比我一直想象的更邪恶......它不仅仅是“如果它看起来像一个函数声明,它就是一个函数声明”,而且“如果它看起来像一个无效的函数声明,它就是一个函数声明” “....omfg (2认同)
  • @ tobi303:看一下语法.它将数组大致定义为`type name_optional [size_expression]`,并且对于求值为零的表达式没有特殊的语法规则.但是,由于C++中的表达式评估是图灵完备的,因此非常难. (2认同)

mol*_*ilo 7

我相信这是从"声明语法就像表达式语法"原理,以及"数组"参数是指针的事实.

以下数组声明是等效的:

int x[1];
int (x)[1];
int (x[1]);
Run Code Online (Sandbox Code Playgroud)

或多或少因为x[a],(x)[a](x[a])是等同的表达.

从而,

std::stringstream ss(std::string(argv[0]))

                 <=>

std::stringstream ss(std::string argv[0])

                 <=>

std::stringstream ss(std::string* argv)
Run Code Online (Sandbox Code Playgroud)