C++添加explicit构造函数致构造失败的编译器匹配问题
C++构造函数重载匹配场景解析
测试代码如下:
#include <iostream> using namespace std; class Y { public: Y(int) {} }; class X { public: X(int, int, Y) { cout << "Y\n"; } // 取消下方注释会触发编译错误 //explicit X(int, int, int) { cout << "3 ints\n"; } }; int main() { X x({ 1, 2, 3 }); }
场景1:注释explicit X(int, int, int)时,代码正常输出Y的原理
这个场景下编译器的重载决议逻辑如下:
- 语句
X x({1,2,3})属于直接初始化,传入的实参是花括号包裹的初始化列表{1,2,3},由于X没有定义接收initializer_list的构造函数,编译器会尝试将列表内的3个元素按顺序匹配X构造函数的形参。 - 对可用构造
X(int, int, Y)做匹配校验:前两个元素1、2是int类型,和前两个形参类型完全匹配;第三个元素3是int类型,可以通过Y的非explicit单参构造Y(int)隐式生成Y类临时对象,匹配第三个形参。 - 没有其他优先级更高的可行构造函数,因此编译器选择该构造,执行后输出
Y。
场景2:取消explicit X(int, int, int)注释后编译报错的原理
这里涉及两个核心C++规则:
- 第一,
explicit关键字修饰的构造函数,仅能在直接列表初始化(即X x{1,2,3}这种初始化器直接为花括号列表的形式)、显式调用构造的场景下使用,无法在任何需要隐式转换的场景参与重载匹配。 - 第二,重载决议的流程是先对所有可行候选按转换优先级排序,选出优先级最高的最佳候选;如果最佳候选因
explicit、访问权限私有、函数被删除等原因无法调用,编译器会直接报错,不会退而求其次选择优先级更低的候选。
具体到这个场景:
- 编译器枚举所有可行构造时,两个三参构造都会被纳入匹配范围:
- 对
X(int, int, int):列表三个元素都是int,和三个形参完全匹配,转换序列是优先级最高的精确匹配。 - 对
X(int, int, Y):前两个参数精确匹配,第三个参数需要经过用户自定义转换(int→Y),优先级低于精确匹配。
- 对
- 重载决议会将
X(int, int, int)选为最佳候选,但该构造被explicit修饰,当前X x({1,2,3})的初始化形式不属于允许explicit构造调用的直接列表初始化场景,该候选无法使用。 - 编译器不会再选择优先级更低的
X(int, int, Y),直接抛出无合适构造函数的编译错误。
补充验证:如果把初始化语句改成
X x{1,2,3}(去掉外层小括号,使用直接列表初始化),explicit修饰的三int构造就可以正常被调用,会输出3 ints。
内容的提问来源于stack exchange,提问作者CPPL
相关产品推荐
相关产品推荐

