使用参数调用类构造函数 - 请求“x”中的非类类型成员 [英] Calling class constructor with parameter - request of a member in 'x' which is of non-class type

查看:119
本文介绍了使用参数调用类构造函数 - 请求“x”中的非类类型成员的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个接受类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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆