在将匿名对象作为参数传递时,不会调用任何构造函数

Viv*_*vek 6 c++ c++11

#include <iostream>

struct Box
{
    Box()            { std::cout << "constructor called" << std::endl; }
    Box(const Box&)  { std::cout << "Copy constructor called" << std::endl; }
    Box(Box&&)       { std::cout << "Move constructor called" << std::endl; }
    void run() const { std::cout << "Run" << std::endl;}
};

int main()
{
    Box a(Box());
    a.run();
}
Run Code Online (Sandbox Code Playgroud)

(演示)

在上面的代码我期待任一Copy ConstuctorMove Constructor在经过匿名对象被调用Box()作为参数.但他们都没有被召唤.原因可能是copy elision.但是甚至没有为匿名对象调用构造函数A().实际上,上面的代码没有编译,并且在调用run()函数编译器时给出了以下错误.

a.cpp: In function ‘int main()’:
a.cpp:28:7: error: request for member ‘run’ in ‘a’, which is of non-class type ‘Box(Box (*)())’
     a.run();
Run Code Online (Sandbox Code Playgroud)

那么当我们输入Box a(Box())正在发生的事情时?正在创造什么?

YSC*_*YSC 15

这是最令人烦恼的解析案例.什么东西可以解析为函数声明,它是.

Box a(Box())
Run Code Online (Sandbox Code Playgroud)

是一个函数的声明,命名为a将类型的函数Box (*)()作为参数并返回一个Box.

解决方案是使用(C++ 11中的新增功能)聚合初始化来构造对象:

Box a{Box{}}
Run Code Online (Sandbox Code Playgroud)

(演示)


MVP以最简单的形式讨论了这个stackoverflow问题最烦恼的解析:为什么不是A a(()); 工作?

如果你有一个表达式,那么它是有效的.例如:

((0));//compiles
Run Code Online (Sandbox Code Playgroud)

要了解有关如何定义语言以及编译器如何工作的更多信息,您应该了解正式语言理论或更具体的上下文无关语法(CFG)和相关材料(如有限状态机).如果你对此感兴趣,虽然维基百科页面还不够,你将不得不得到一本书.