为何C++中用临时默认构造对象初始化会声明函数而非变量?
解析C++中
A x2(A());被解析为函数声明的原因 这是C里大名鼎鼎的**最令人头疼的解析(Most Vexing Parse)**问题,属于C语法规则里的经典陷阱,我来给你拆解清楚:
首先先看你的测试代码:
#include <iostream> struct A { // constructor 1 A() { std::cout << "A() called" << std::endl; } // constructor 2 A(const A&) { std::cout << "A(const A&) called" << std::endl; } }; int main() { // statement 1 A x1; // statement 2 A x2( A() ); return 0; }
为什么语句2会被解析为函数声明?
C++的语法规则有一个核心优先级:当一段代码既可以被解析为对象定义,又可以被解析为函数声明时,编译器会优先选择函数声明。
具体到A x2( A() );这句话:
- 开头的
A x2(...)会被编译器首先识别为「函数声明」的开头,函数名为x2,返回值类型是A - 括号内的
A()不会被看作是「创建一个临时A对象」,而是被解析为函数指针类型:表示一个「无参数、返回值为A的函数」的指针。
所以整个语句最终被解析为:
// 函数x2,接受一个指向无参返回A的函数的指针,返回A类型对象 A x2( A (*)() );
这就是为什么你看不到构造函数2被调用——因为根本没有创建x2对象,只是声明了一个函数。
如何解决这个问题?
针对不同的C++标准,有几种可靠的方式避免这个陷阱:
1. C++11及以后:使用列表初始化(大括号)
把语句改成:
A x2{ A() };
大括号初始化语法会强制编译器将其解析为对象初始化,不会被误判为函数声明,此时会正常调用无参构造创建临时对象,再调用拷贝构造(C++17及以后可能会被优化为直接调用无参构造,但语法上是合法的对象创建)。
2. 给临时对象添加额外括号
通过内层括号打破函数声明的解析逻辑:
A x2( (A()) );
额外的括号让(A())只能被看作是一个表达式(创建临时A对象),而不是函数参数声明,编译器就会正确解析为对象初始化。
3. 使用拷贝初始化语法
改成拷贝初始化形式:
A x2 = A();
这种写法也不会被解析为函数声明,会正常触发拷贝构造(同样可能被编译器优化)。
内容的提问来源于stack exchange,提问作者AJ Tan
相关产品推荐
相关产品推荐

