【问题标题】:How to deal with noexcept in Visual Studio如何在 Visual Studio 中处理 noexcept
【发布时间】:2013-08-25 14:36:12
【问题描述】:

我正在尝试创建一个派生自 std::exception 并覆盖 what() 的自定义异常。一开始我是这样写的:

class UserException : public std::exception
{
private:
    const std::string message;
public:
    UserException(const std::string &message)
        : message(message)
    {}

    virtual const char* what() const override
    {
        return message.c_str();
    }
};

这在 VS2012 中运行良好,但在带有 -std=c++11 的 GCC 4.8 中无法编译:

错误:'virtual const char* UserException::what() const'的更宽松的抛出说明符

所以我加了noexcept:

virtual const char* what() const noexcept override

这在 GCC 中运行良好,但在 Visual Studio 中无法编译(因为 VS 2012 不支持 noexcept):

错误 C3646:“noexcept”:未知覆盖说明符

推荐的处理方法是什么?我想用两个编译器编译相同的代码,而且我正在使用 C++11 功能,所以我不能用不同的-std 编译。

【问题讨论】:

    标签: c++ visual-studio-2012 c++11 noexcept


    【解决方案1】:

    使用宏

    #ifndef _MSC_VER
    #define NOEXCEPT noexcept
    #else
    #define NOEXCEPT
    #endif
    

    然后将函数定义为

    virtual const char* what() const NOEXCEPT override
    

    您还可以通过检查_MSC_VER 的值来修改它以允许noexcept 在更高版本的VS 上使用;对于 VS2012,该值为 1600。

    【讨论】:

    • 根据this video (look at the table at 58:00),VS2013不支持noexcept
    • 另外,VS 版本使用#define NOEXCEPT throw() 有意义吗?
    • @svick 两者之间的行为略有不同。从标记为throw() 的函数中抛出将调用std::unexpected,而如果标记为noexcept,则将调用std::terminate;但在您的用例中,两者应该是等价的。但是,MSDN page for std::exception 并不表示what() 被标记为throw(),因此如果将异常规范添加到覆盖函数中,您可能会遇到警告或错误。
    【解决方案2】:

    #IFs 可能有效,即使有点 hacky。

    你可以这样做:

    #if __GNUG__
    virtual const char* what() const noexcept override
    #else
    virtual const char* what() const override
    #endif
    //method body
    

    【讨论】:

      【解决方案3】:

      似乎旧的throw()(在 C++11 中已弃用)在两种编译器中都有效。所以我把代码改成:

      virtual const char* what() const throw() override
      

      【讨论】:

      • 但这不是一回事。它是否消除了looser throw specifier for ‘virtual const char* UserException::what() const’ 错误?
      • @VáclavZeman 是的,据我所知,这确实对我有用。
      【解决方案4】:

      此检查用于查看是否支持 noexcept

      // Is noexcept supported?
      #if defined(__clang__) && __has_feature(cxx_noexcept) || \
          defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ * 10 + __GNUC_MINOR__ >= 46 || \
          defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 180021114
      #  define NOEXCEPT noexcept
      #else
      #  define NOEXCEPT
      #endif
      

      以上内容适用于 Clang、GCC 和 MSVC。

      【讨论】:

      • 嗯,MSVC 2010 没有noexcept,是吗?它的_MSC_VER1600,小于1800,因此NOEXCEPT 应该扩展为空。您遇到了什么问题?
      • warning C4067: unexpected tokens following preprocessor directive - expected a newline。看起来 `__has_feature(cxx_noexcept)` 出于某种原因混淆了它。当我删除它时,它工作正常。编辑:我现在意识到我将警告视为错误,这只是一个警告。如果我抑制 4067 它毕竟可以工作。
      • 180021114 好像是VS2013,不支持noexcept。 ivan.ukr 的值 190023026 对我来说效果更好。
      【解决方案5】:

      noexcept 是 MSVC 最容易处理的“缺陷”之一:只需使用宏 _NOEXCEPT,它在 MSVC2013 下定义在 yvals.h 中。

      【讨论】:

      • 但我并不是在寻找只适用于 VS 的解决方案,而是寻找一种适用于任何地方(或至少适用于 VS 和 GCC)的解决方案。
      • facepalm 那么@svick 然后使用我刚刚给你的宏并将它与 C++11 中的 noexcept 结合起来,瞧,你将有一个可行的解决方案到处! :D
      【解决方案6】:

      在 Visual Studio 中的代码中添加以下行:

      #ifdef _NOEXCEPT
      #define noexcept _NOEXCEPT
      #endif
      

      【讨论】:

      • 这是错误的。您正在定义一个与保留关键字具有相同文字的宏,这是被禁止的。
      • 这在 VS 中工作以引入两个版本之间的兼容性。
      • 即使在 C++11 之前的 Visual Studio 版本中,noexcept 也是保留关键字。您会在编译期间收到警告。在这种情况下,我建议使用大写 NOEXCEPT。
      • 如果未定义,将_NOEXCEPT 定义为noexcept 不是更好吗? (所以在 MSVC 中编译时使用 VS 的版本,在其他编译器中使用 C++11 的版本。)
      【解决方案7】:

      "noexcept" 自 Visual Studio 2015 起才受支持(如此处所述:https://msdn.microsoft.com/en-us/library/wfa0edys.aspx)。 我在 Visual Studio 2013 中使用了以下代码(源自上述示例):

      #if !defined(HAS_NOEXCEPT)
      #if defined(__clang__)
      #if __has_feature(cxx_noexcept)
      #define HAS_NOEXCEPT
      #endif
      #else
      #if defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ * 10 + __GNUC_MINOR__ >= 46 || \
          defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026
      #define HAS_NOEXCEPT
      #endif
      #endif
      
      #ifdef HAS_NOEXCEPT
      #define NOEXCEPT noexcept
      #else
      #define NOEXCEPT
      #endif
      

      【讨论】:

      • 创建一些头文件,将其包含在您计划使用的所有位置。
      【解决方案8】:

      另一种解决方法是创建头文件,并在必要时将其包含在应由 gcc、vc 或 clang 编译的源代码中。

      no_except_work_around.h

      #ifndef no_except_work_around_H
      #define no_except_work_around_H
      
      #if (_MSC_VER <= 1800)
      #include <xkeycheck.h>
      #define noexcept
      #endif 
      
      #endif //no_except_work_around_H
      

      ================================================ ======

      P.S> 不包括案例 无例外(假) 但适用于 VC2010,2012,2013, gcc 4.9

      【讨论】:

      • 您可以开始使用 noexcept 的优势,并且在继续使用 VC 2015 之后,只需删除代码中的标头即可:#include "no_except_work_around.h"
      【解决方案9】:

      我最近使用的如下:

      #ifdef _MSC_VER
      #define NOEXCEPT _NOEXCEPT
      #else
      #define NOEXCEPT noexcept
      #endif
      

      然后在任何地方都使用NOEXCEPT

      【讨论】:

        【解决方案10】:

        &lt;boost/config.hpp&gt; 中使用BOOST_NOEXCEPT

        boost 配置库是为解决此类兼容性问题而设计的。根据the doc

        如果定义了 BOOST_NO_CXX11_NOEXCEPT(即符合 C++03 的编译器),则这些宏定义为:

            #define BOOST_NOEXCEPT
            #define BOOST_NOEXCEPT_OR_NOTHROW throw()
            #define BOOST_NOEXCEPT_IF(Predicate)
            #define BOOST_NOEXCEPT_EXPR(Expression) false
        

        如果 BOOST_NO_CXX11_NOEXCEPT 未定义(即符合 C++11 的编译器),则它们被定义为:

            #define BOOST_NOEXCEPT noexcept
            #define BOOST_NOEXCEPT_OR_NOTHROW noexcept
            #define BOOST_NOEXCEPT_IF(Predicate) noexcept((Predicate))
            #define BOOST_NOEXCEPT_EXPR(Expression) noexcept((Expression))
        

        这里的许多其他答案都有类似的实现,但是这个库更干净,经过更好的测试,并且在升级编译器时会做正确的事情。我建议总体上查看 boost 配置库的其他功能,尤其是在这个语言不断变化和编译器支持水平不同的时代。

        【讨论】:

          【解决方案11】:

          将以下路径添加到其他包含目录

          C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include
          

          在这个位置有一个名为“yvals.h”的文件,其中包含_NOEXCEPT的定义

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-09-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多