MSVC、Clang报歧义函数调用错误,GCC无错,谁符合C++标准?
C++标准合规性分析:不同编译器对删除默认构造函数类的列表初始化行为
核心场景
- 当
BaseImpl显式删除默认构造函数,派生类impl通过BaseImpl({})初始化基类时:MSVC、Clang编译报错,GCC编译通过。 - 当显式删除
BaseImpl的拷贝构造函数,或不删除默认构造函数时,三款编译器均能正常编译。
标准判定
根据C++标准的明确规则:
- 聚合体的定义:类只要存在用户声明的构造函数(包括用
=delete显式删除的构造函数),就不属于聚合体。因此,显式删除默认构造函数的BaseImpl不是聚合体。 - 非聚合体的列表初始化:对于非聚合体类,使用空初始化列表
{}初始化对象时,必须调用类的默认构造函数。如果默认构造函数被显式删除(不可调用),这种初始化属于编译错误,编译器必须拒绝。
结论:
- MSVC和Clang的行为符合C++标准:它们正确识别到
BaseImpl({})尝试调用已删除的默认构造函数,因此抛出错误。 - GCC的行为不符合标准:它允许了这种无效的初始化操作,属于编译器的非标准扩展行为。
特殊场景的原因
- 不删除默认构造函数:
BaseImpl({})直接调用可用的默认构造函数,完全符合标准,所以三款编译器都通过。 - 显式删除拷贝构造函数:此时三款编译器均通过的原因,大概率是编译器内部的特殊处理(比如对空类的初始化逻辑优化),但严格来说这种处理并不符合标准对非聚合体初始化的要求。
内容的提问来源于stack exchange,提问作者WhoAmI
相关产品推荐
相关产品推荐

