【问题标题】:C2694 on destructor when base class' member's destructor has non-empty noexcept specifier and a body当基类成员的析构函数具有非空 noexcept 说明符和主体时,析构函数上的 C2694
【发布时间】:2017-05-15 02:46:23
【问题描述】:

我遇到了无法解释的编译器错误,也无法在网上找到相关信息。我最近在包装类的析构函数中添加了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;
};

sn-p 产生以下错误信息:

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 析构函数可以避免编译器错误,但这感觉像是一种不必要的解决方法。实际上,当您考虑到每个派生类都必须更新时,这也是一个相当大的负担。

【问题讨论】:

  • 让赞成票自己说话,但这是一个很好的问题。谢谢,祝你好运
  • Fwiw,除了 gcc 4.9,它还在语言级别 c++14 下通过了 clang 3.8,没有任何问题。
  • 看起来像一个编译器错误。
  • 我确信这个问题可以得到改进 - 但我认为我们最好担心最后 1000 个首先提出的问题中的 999 个较差的问题。

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


【解决方案1】:

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

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 也受到影响。

【讨论】:

    猜你喜欢
    • 2021-09-14
    • 2013-03-21
    • 1970-01-01
    • 2016-07-07
    • 1970-01-01
    • 2018-06-29
    • 2016-09-19
    • 1970-01-01
    相关资源
    最近更新 更多