使用参数调用类构造函数 - 请求“x”中的非类类型成员 [英] Calling class constructor with parameter - request of a member in 'x' which is of non-class type
问题描述
我有一个接受类B作为构造函数参数的类A. B类可以用int值构造。我原来的代码非常复杂,但我希望我已经将它简化为基本情况:
class B {
public:
explicit B(int a):val(a){}
private:
int val;
};
$ b $ class A {
public:
A(const B& val):value(val){};
void print(){
//不做任何事
}
private:
B值;
};
int main(){
int someTimeVar = 22;
A a(B(someTimeVar));
.print();
}
这是我得到的错误代码:
$ g ++ test.cpp -Wall -O0
test.cpp:在函数'int main()'中:
test .cpp:22:7:error:请求'a'中的成员'print',它是非类类型'A(B)'
a.print();
^
test.cpp:20:9:warning:未使用的变量'someTimeVar'[-Wunused-variable]
int someTimeVar = 22;
$
我使用GCC(4.9.2 20150304(预发布)),platform:arch
对主函数进行的以下修改可以很好地编译:
int main(){
A a(B(22));
.print();
}
我很清楚使用A a();声明一个函数,而不是一个对象。但我没想到A a(B(some_val))也会这样做,并且我认为这是发生在这里的事情。
你有什么想法这是怎么回事?
编辑:感谢所有的答案,看起来我需要更多地研究最令人头疼的解析思路。 p>
顺便说一句,使用clang编译我的代码会提供更有用的错误信息和解决方案:
$ clang test.cpp
test.cpp:21:8:warning:圆括号被解析为函数声明[-Wvexing-parse]
A a(B(someTimeVar)) ;
^ ~~~~~~~~~~~~~~~
test.cpp:21:9:注意:添加一对圆括号来声明变量
A a( B(someTimeVar));
()
test.cpp:22:6:error:成员引用基类型'A(B)'不是结构体或联合体
a.print() ;
〜^ ~~~~~
1个警告和1个错误产生。
这个问题在stackoverflow上有自己的标记。最令人烦恼的解析
维基百科对问题及其解决方案进行了清晰的描述。 https://en.wikipedia.org/wiki/Most_vexing_parse 。
行
TimeKeeper time_keeper(Timer());
可以被解释为:
- TimeKeeper类的变量time_keeper的变量定义,传递类Timer的匿名实例或
- 函数time_keeper的函数声明,返回TimeKeeper类型的对象,有一个单一的(未命名的)参数
是一个返回类型Timer的函数(并且没有输入)。 (请参阅
函数对象#在C和C ++中)
大多数程序员都期待第一个,但C ++标准要求它
被解释为第二个。
解决方法是将括号添加到参数中:
A a((B(22)));
或者像其他人指出的那样使用通用初始化,如
A a {B {22}};
I have a class A that accepts class B as a constructor parameter. Class B can be constructed from int value. My original code is quite complex, but I hope I've reduced it to the very base case:
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();
}
And this is the error code I'm getting:
$ 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;
^
I use GCC (4.9.2 20150304 (prerelease)), platform: arch linux.
The following modification to the main function compiles fine:
int main() {
A a(B(22));
a.print();
}
I'm well aware that using A a(); declares a function, not a object. But I didn't expect that A a(B(some_val)) will do the same, and in my opinion this is what's happening here.
Do you have ideas why this is happening?
Edit: Thank you for all the answers, looks like I need to research more on most vexing parse idea.
BTW it turns out that compiling my code using clang provides more useful error message plus a solution:
$ 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.
This problem has its own tag here on stackoverflow. most-vexing-parse
Wikipedia har a clear description of the problem and its solution. https://en.wikipedia.org/wiki/Most_vexing_parse.
The line
TimeKeeper time_keeper(Timer());
could be disambiguated either as
- a variable definition for variable time_keeper of class TimeKeeper, passed an anonymous instance of class Timer or
- a function declaration for a function time_keeper which returns an object of type TimeKeeper and has a single (unnamed) parameter which is a function returning type Timer (and taking no input). (See Function object#In C and C++)
Most programmers expect the first, but the C++ standard requires it to be interpreted as the second.
The solution is to add parenthesis to the argument like:
A a( (B(22)) );
or as others have noted use universal initialization like
A a { B{22} };
这篇关于使用参数调用类构造函数 - 请求“x”中的非类类型成员的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!