C2694 在析构函数上,当基类成员的析构函数具有非空 noexcept 说明符和主体时
C2694 on destructor when base class' member's destructor has non-empty noexcept specifier and a body
我遇到了一个编译器错误,我无法解释,也无法在线找到有关它的信息。我最近在包装类的析构函数中添加了一个noexcept
说明符,现在大量从使用此包装器的类继承的类都无法编译。我已经用GCC 4.9尝试过,没有编译器错误。
我正在使用 Visual Studio Professional 2015 版本 14.0.25431.01 Update 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:usersfandrieuxworkspacetmpdtor_noexceptmain.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:usersfandrieuxworkspacetmpdtor_noexceptmain.cpp(19): note: compiler has generated 'derived::~derived' here
1> c:usersfandrieuxworkspacetmpdtor_noexceptmain.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也受到影响。
- 什么时候调用组成单元对象的析构函数
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 内联映射初始化的动态atexit析构函数崩溃
- 什么时候调用析构函数
- 优先顺序:智能指针和类析构函数
- C++-明确何时以及如何调用析构函数
- 使用基类指针创建对象时,缺少派生类析构函数
- 在c++中使用向量时,如何调用构造函数和析构函数
- 重载运算符new[]的行为取决于析构函数
- 我需要知道编译器如何在cpp中使用析构函数
- 为什么在使用转换构造函数赋值后调用C++类的析构函数?
- 析构函数调用
- 通过引用传递-为什么要调用这个析构函数
- C2694 在析构函数上,当基类成员的析构函数具有非空 noexcept 说明符和主体时
- 为什么noexcept构造函数需要析构函数的实例化
- g++-4.8.1认为没有异常说明的显式声明的析构函数总是noexcept(true)
- 正在转换到C++11,其中析构函数是用noexcept隐式声明的
- 向后兼容析构函数的noexcept(false)
- 析构函数和noexcept
- noexcept(false)析构函数覆盖所有特殊成员函数'异常规范