我遇到无法解释的编译器错误,也无法在线找到有关该错误的信息。我最近noexcept
在包装器类的析构函数中添加了一个说明符,现在大量从使用该包装器的类继承的类无法编译。我已经在GCC 4.9上尝试过了,没有编译器错误。
我正在使用Visual Studio Professional 2015版本14.0.25431.01更新3
请考虑下面的重现此问题的最小代码:
#include <type_traits>
template<class T>
struct member
{
~member() noexcept(std::is_nothrow_destructible<T>::value) {};
};
struct parent
{
virtual ~parent() noexcept = default;
};
struct derived : public parent
{
member<int> x;
};
该代码段产生以下错误消息:
1>c:\users\fandrieux\workspace\tmp\dtor_noexcept\main.cpp(19): error C2694: 'derived::~derived(void) noexcept(<expr>)': overriding virtual function has less restrictive exception specification than base class virtual member function 'parent::~parent(void) noexcept'
1> c:\users\fandrieux\workspace\tmp\dtor_noexcept\main.cpp(19): note: compiler has generated 'derived::~derived' here
1> c:\users\fandrieux\workspace\tmp\dtor_noexcept\main.cpp(12): note: see declaration of 'parent::~parent'
我发现有趣的是,如果您用= default
或使用noexcept
或替换成员的析构函数主体,则编译器错误会消失noexcept(true)
:
// None of these produce compiler errors
virtual ~member() noexcept(std::is_nothrow_destructible<T>::value) = default;
virtual ~member() noexcept(true) {}
virtual ~member() noexcept {}
我知道它的析构函数不会抛出。偏执狂和怀疑论者(像我一样)可以添加以下静态断言,并对其进行检查:
static_assert(std::is_nothrow_destructible<T>::value, "Might throw!");
根据MSDN,这表明动态异常说明符不足。这在这里如何适用?不noexcept([boolean expression])
等于noexcept(true)
或等于noexcept(false)
吗?为什么这种变化取决于功能体的存在?在派生对象上添加显式的noexcept析构函数可以避免编译器错误,但这似乎是不必要的解决方法。实际上,当您考虑必须更新每个派生类时,这也是一个负担。
这看起来像是编译器错误。如果我们添加以下类:
struct dtor_throws
{
~dtor_throws() noexcept(false) {}
};
从而改变定义derived
:
struct derived : public parent
{
member<dtor_throws> x;
};
然后GCC和Clang都抱怨的异常规范~derived
比宽松~parent
。
在原始示例中,MSVC似乎没有将表达式的值嵌入的noexcept
类型~parent
,而只是将noexcept
用户定义的类模板的析构函数的所有复合规范视为比宽松noexcept(true)
。
MSVC 2017 RC也受到影响。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句