以下代码不在gcc-4.7.1下编译,而是在clang-3.2下编译.哪一个遵循C++ 11标准?
struct X {
virtual ~X() = default;
};
struct Y : X {
virtual ~Y() = default;
};
Run Code Online (Sandbox Code Playgroud)
gcc-4.7.1抱怨说:
looser throw specifier for 'virtual Y::~Y()'
error: overriding 'virtual X::~X() noexcept(true)'
Run Code Online (Sandbox Code Playgroud)
显然,gcc-4.7.1认为X的默认析构函数是nothrow,但是Y的默认析构函数并不是没有.为什么是这样?任何人都可以参考标准中的正确位置吗?谢谢.
我在stackoverflow上看到了类似的问题,但我没有看到参考标准的答案.
jog*_*pan 37
由于以下原因,编译器陷入两难境地:
(1)在函数声明中没有指定任何异常(即不使用thrownor noexcept(相当于noexcept(true)))意味着允许该函数抛出所有可能的异常:
(§15.4/ 12,强调我的)一种没有例外规定的函数,或者具有异常规范的函数,
noexcept(constant-expression)其中constant-expression产量false允许所有异常.[...]
(2)默认析构函数必须准确允许由其隐式定义直接调用的函数允许的异常:
(§15.4/ 14,强调我的)隐含声明的特殊成员函数(第12条)应具有例外规范.如果f是隐式声明的默认构造函数,复制构造函数,移动构造函数,析构函数,复制赋值运算符或移动赋值运算符,则其隐式异常规范指定了类型ID,当且仅当T被例外规范允许时才允许由f的隐式定义直接调用的函数 ; 如果它直接调用的任何函数允许所有异常,则f应允许所有异常,如果它直接调用的每个函数都不允许异常,则f不允许异常.
(3)当一个特殊成员(例如析构函数)被明确默认时,即当你使用时= default,异常规范是可选的(参见下面" 可能有" 的使用):
(8.4.2/2,强调我的)明确默认的函数 [...] 只有在与隐式声明的异常规范兼容(15.4)时才有明确的异常规范.[...]
标准中没有声明需要在显式默认的析构函数中使用异常规范.
结论:因此,不指定明确默认的析构函数的异常可以用两种方式解释:
不幸的是,在你的基类声明的情况下,GCC以一种方式(支持"无例外")解决了这种困境,并且在派生类的情况下以不同的方式解决了这种困境(支持那里的"所有例外").
我认为对这种公认的模糊情况的最自然的解释是假设(2)和(3)重写(1).标准没有这样说,但应该如此.根据这种解释,Clang似乎就在这里.