C2694关于析构函数的基类' member'析构函数具有非空的noexcept说明符和正文

时间:2016-12-30 20:32:25

标签: c++ visual-studio visual-studio-2015

我遇到编译错误,我无法解释,也无法在线查找有关它的信息。我最近在包装类的析构函数中添加了一个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:\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替换成员的析构函数体,或者使用noexceptnoexcept(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!");

According to MSDN它表示动态异常说明符不足。这在哪里适用?不是noexcept([boolean expression])等同于noexcept(true)noexcept(false)吗?为什么这会根据函数体的存在而改变?添加一个显式的noexcept析构函数来导出编译器错误,但这感觉就像一个不必要的解决方法。在实践中,当您考虑必须更新每个派生类时,它也是一个很大的负担。

1 个答案:

答案 0 :(得分:6)

这看起来像编译器错误。如果我们添加以下类:

struct dtor_throws
{
    ~dtor_throws() noexcept(false) {}
};

然后改变derived的定义:

struct derived : public parent
{
    member<dtor_throws> x;
};

然后GCC和Clang都抱怨~derived的异常规范比~parent宽松。

在原始示例中,MSVC似乎没有在noexcept的类型中嵌入~parent表达式的,而只是处理所有复合{{1}用户定义的类模板析构函数的规范比noexcept更宽松。

MSVC 2017 RC也受到影响。