考虑这个简短的片段:
struct B {
B() = default;
explicit B(B const& ) { }
};
struct D : B { };
int main() {
try {
throw D{};
}
catch(B ) {
}
}
GCC 接受此代码,Clang 认为其格式不正确:
main.cpp:17:13: error: no matching constructor for initialization of 'B'
catch(B ) {
^
谁是对的?
我认为这是一个 gcc 错误(由于还没有人对这个答案投反对票,所以我将其提交为 70375)。
两个编译器都正确地同意应该按照 [except.handle]/3 捕获D{}
,它只检查B
是 D
的基类。
但是处理程序的初始化在 [except.handle]/15 中定义为:
由异常声明声明的 cv
T
或 cvT&
类型的变量从E
类型的异常对象初始化,如下所示:
— 如果T
是E
的基类,则变量从异常对象的相应基类子对象复制初始化 (8.5);
这意味着初始化的工作方式为:
D __temporary_object{};
B __handler = static_cast<B&>(__temporary_object);
这应该是不允许的,因为B
的复制构造函数被标记为explicit
(并且复制初始化只是不会削减它)。