使用参数调用类构造函数 - 在' x'中成员的请求这是非类型的

时间:2015-06-23 12:40:57

标签: c++ gcc most-vexing-parse

我有一个接受B类作为构造函数参数的A类。 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();
}

这是我得到的错误代码:

$ 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;
         ^

我使用GCC(4.9.2 20150304(预发布)),平台:arch linux。

主函数的以下修改编译正确:

int main() {
    A a(B(22));
    a.print();
}

我很清楚使用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.

3 个答案:

答案 0 :(得分:7)

A a(B(someTimeVar))被解释为A a(B someTimeVar),因此a是一个接受B类型参数并返回A的函数。

这是向C ++ 11添加统一初始化的原因之一:

A a{B{someTimeVar}};

答案 1 :(得分:6)

此问题在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} }; 

答案 2 :(得分:2)

A a(B(someTimeVar));声明一个返回类型为A的函数和一个名为someTimeVar的类型为B的参数。它与A a(B someTimeVar);

相同

它适用于A a(B(22));,因为22不是有效的标识符,因此函数声明无效。

如果您的代码库使用C ++ 11(或更新版本),您可以使用花括号进行统一初始化:A a(B{someTimeVar});