似乎语言的歧义性问题总是难以避免的,连C++语言都不可避免。
如果没记错,CFG文法在规约过程是存在歧义的?所以C++也就无法避免的会遇到语法歧义的问题。这个被称为Most Vexing Parse
就是C++语言在遇到某一句法歧义时特定的决策方法(翻译自维基百科, 提供英文以防止错译:The most vexing parse is a specific form of syntactic ambiguity resolution in the C++ programming language. )。
在之前写代码的过程中就曾遇到过这个问题: 定义一个拥有默认构造函数的对象,使用一下的方式(不正确的):
ClassName m();
编译器并不会解释m
为一个ClassName
对象,而是一个 返回ClassName
、接收空参数的函数(整句被解释为一个函数声明)。
上述问题已经是很久遇到的了,开始也是迷迷糊糊,发现去掉括号就好使了,后来几经踩坑,才算明白问题的根本原因以及编译器的苦衷。只是,不想今天遇到了更加Vexing
的形式。
我要定义一个最小堆,如下:
priority_queue<int, vector<int>, greater<int>> minHeap(greater<int>(), vector<int>());
上述定义没有报错,但是我一调用minHeap.size();
编译器就报错:
error: request for member 'size' in 'minHeap', which is of non-class type 'std::priority_queue<int, std::vector<int>, std::greater<int> >(std::greater<int> (*)(), std::vector<int> (*)())'
minHeap.size();
实在太长了,我一时没有看清,直到搜到了爆栈上的相似问题:c++ could not pass argument to std::priority_queue constructor , 看到里面提到的 Most Vexing Parse
, 才明白又是这个问题。
即, 上面还是定义了 1 个minHeap
的函数,只不过,它的参数类型都太「奇怪」了: greater<int>()
指定了一个函数类型:入参是空,返回参数是greater<int>
;
而 vector<int>()
同理; 是不是太 Vexing
了……
先说说针对这个问题的解决办法,我觉得有3种吧:
-
根本不需要传递构造函数参数。
直接用 priority_queue<int, vector
, greater > minHeap; 即可 -
给每个参数多加一对括号。
priority_queue<int, vector<int>, greater<int>> minHeap((greater<int>()), (vector<int>()));
没有查原因,我想因为是小括号优先级高啊,先解释得到匿名对象,然后再解释minHeap,就消除了歧义,其再不能被解释为函数声明了。
-
使用C++11的
Uniform Initialization Syntax
(维基百科中的通用方法)即是使用花括号。
priority_queue<int, vector<int>, greater<int>> minHeap{greater<int>{}, vector<int>{}};
不过使用这个也可能带来歧义,如:
vector<int>{4};
上述其实是生成了一个包含1个元素的vector,该元素初值为4;而非vector
(4), 生成4个初值为0的vector。 想来,这个方法也不算太值得推荐。
最后,再看Most Vexing Parse
。目前我还没有看到中文的翻译。如果没有理解错,感觉可以译为最复杂生成,即按照最让人厌烦的方式分析语句。不过这可能也仅仅表示这种分析是让人Vexing
的?犹记得当年英语老师叮嘱ing表示事物的性质,ed表示人的感受,这么来说还是第一种有道理啊。应该是C++制定人员觉得让你瞎写,就给你最复杂的解析,让你懵逼。咳,感觉这个可以作为一个面试C++的题,应该可以分类那些写代码和不写代码的人,哈哈哈。