kam*_*ilm 4 c++ gcc most-vexing-parse
我有一个类A接受B类作为构造函数参数.B类可以用int值构造.我原来的代码非常复杂,但我希望我把它简化为基本情况:
class B {
public:
explicit B(int a) : val(a) {}
private:
int val;
};
class A {
public:
A(const B & val) : value(val) {};
void print() {
//does nothing
}
private:
B value;
};
int main() {
int someTimeVar = 22;
A a(B(someTimeVar));
a.print();
}
Run Code Online (Sandbox Code Playgroud)
这是我得到的错误代码:
$ g++ test.cpp -Wall -O0
test.cpp: In function ‘int main()’:
test.cpp:22:7: error: request for member ‘print’ in ‘a’, which is of non-class type ‘A(B)’
a.print();
^
test.cpp:20:9: warning: unused variable ‘someTimeVar’ [-Wunused-variable]
int someTimeVar = 22;
^
Run Code Online (Sandbox Code Playgroud)
我使用GCC(4.9.2 20150304(预发布)),平台:arch linux.
主函数的以下修改编译正常:
int main() {
A a(B(22));
a.print();
}
Run Code Online (Sandbox Code Playgroud)
我很清楚使用A a(); 声明一个函数,而不是一个对象.但我没想到A a(B(some_val))会做同样的事情,在我看来这就是这里发生的事情.
你知道为什么会这样吗?
编辑:谢谢你的所有答案,看起来我需要研究更多关于最烦人的解析思路.
顺便说一句,事实证明使用clang编译我的代码提供了更有用的错误消息和解决方案:
$ clang test.cpp
test.cpp:21:8: warning: parentheses were disambiguated as a function declaration [-Wvexing-parse]
A a(B(someTimeVar));
^~~~~~~~~~~~~~~~
test.cpp:21:9: note: add a pair of parentheses to declare a variable
A a(B(someTimeVar));
^
( )
test.cpp:22:6: error: member reference base type 'A (B)' is not a structure or union
a.print();
~^~~~~~
1 warning and 1 error generated.
Run Code Online (Sandbox Code Playgroud)
A a(B(someTimeVar))被解释为A a(B someTimeVar),a函数采用类型参数B并返回A.
这是向C++ 11添加统一初始化的原因之一:
A a{B{someTimeVar}};
Run Code Online (Sandbox Code Playgroud)
此问题在stackoverflow上有自己的标记.最让人头疼的,解析
维基百科可以清楚地描述问题及其解决方案.https://en.wikipedia.org/wiki/Most_vexing_parse.
这条线
Run Code Online (Sandbox Code Playgroud)TimeKeeper time_keeper(Timer());可以消除歧义
- 类TimeKeeper的变量time_keeper的变量定义,传递了Timer或类的匿名实例
- 一个函数time_keeper的函数声明,它返回一个TimeKeeper类型的对象,并且有一个(未命名的)参数,它是一个返回类型Timer的函数(并且没有输入).(参见C和C++中的函数对象#)
大多数程序员都期望第一个,但C++标准要求它被解释为第二个.
解决方案是在参数中添加括号,如:
A a( (B(22)) );
Run Code Online (Sandbox Code Playgroud)
或者正如其他人所说的那样使用通用初始化
A a { B{22} };
Run Code Online (Sandbox Code Playgroud)