4

我有一个 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();
}

这是我得到的错误代码:

$ 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 (prerelease)),平台:arch linux。

对 main 函数的以下修改编译良好:

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.
4

3 回答 3

7

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

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

A a{B{someTimeVar}};
于 2015-06-23T12:46:51.187 回答
6

这个问题在stackoverflow上有自己的标签。最麻烦的解析

维基百科对问题及其解决方案有清晰的描述。https://en.wikipedia.org/wiki/Most_vexing_parse

线

TimeKeeper time_keeper(Timer());

可以消除歧义

  • TimeKeeper 类的变量 time_keeper 的变量定义,传递了 Timer 类的匿名实例或
  • 一个函数 time_keeper 的函数声明,它返回一个 TimeKeeper 类型的对象,并有一个(未命名的)参数,它是一个返回 Timer 类型的函数(并且不接受输入)。(参见函数对象#In C 和 C++)

大多数程序员期望第一个,但 C++ 标准要求将其解释为第二个。

解决方案是在参数中添加括号,例如:

     A a( (B(22)) );

或者正如其他人所指出的那样使用通用初始化

     A a { B{22} }; 
于 2015-06-23T12:47:42.813 回答
2

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

它之所以起作用,A a(B(22));是因为 22 不是有效标识符,因此函数声明将无效。

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

于 2015-06-23T12:48:03.417 回答