当基类'member'的析构函数具有非空noexcept说明符和body时,析构函数上的C2694

Fra*_*eux 18 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;
};
Run Code Online (Sandbox Code Playgroud)

该代码段产生以下错误消息:

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'
Run Code Online (Sandbox Code Playgroud)

我觉得有趣的是,如果你通过更换成员的析构函数体编译器错误消失= 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 {}
Run Code Online (Sandbox Code Playgroud)

我知道它的析构函数不会抛出.偏执狂和怀疑论者(像我一样)可以添加以下静态断言并自行检查:

static_assert(std::is_nothrow_destructible<T>::value, "Might throw!");
Run Code Online (Sandbox Code Playgroud)

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

Okt*_*ist 6

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

struct dtor_throws
{
    ~dtor_throws() noexcept(false) {}
};
Run Code Online (Sandbox Code Playgroud)

并改变derived这样的定义:

struct derived : public parent
{
    member<dtor_throws> x;
};
Run Code Online (Sandbox Code Playgroud)

然后GCC和Clang都抱怨异常规范~derived~parent.

在原始示例中,MSVC似乎不是将表达式的嵌入到noexcept类型中~parent,而是仅仅将noexcept类模板的用户定义析构函数的所有复合规范视为比较轻松noexcept(true).

MSVC 2017 RC也受到影响.