47
votes

I'm trying to create a custom exception that derives from std::exception and overrides what(). At first, I wrote it like this:

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();
    }
};

This works fine in VS2012, but it doesn't compile in GCC 4.8 with -std=c++11:

error: looser throw specifier for ‘virtual const char* UserException::what() const’

So I add noexcept:

virtual const char* what() const noexcept override

This works fine in GCC, but it doesn't compile in Visual Studio (because VS 2012 doesn't support noexcept):

error C3646: 'noexcept' : unknown override specifier

What is the recommended way to deal with this? I want the same code to compile with both compilers and I'm using C++11 features, so I can't compile with different -std.

11

11 Answers

45
votes

Use a macro

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

And then define the function as

virtual const char* what() const NOEXCEPT override

You could also modify that to allow noexcept on later versions of VS by checking the value of _MSC_VER; for VS2012 the value is 1600.

16
votes

"noexcept" is only supported since the Visual Studio 2015 (as stated here: https://msdn.microsoft.com/en-us/library/wfa0edys.aspx). I have used following code with Visual Studio 2013 (derived from above examples):

#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
12
votes

This check works to see if noexcept is supported:

// 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

The above works with Clang, GCC and MSVC.

10
votes

use BOOST_NOEXCEPT in <boost/config.hpp>

The boost config library was designed for compatibility issues like this. According to the doc:

If BOOST_NO_CXX11_NOEXCEPT is defined (i.e. C++03 compliant compilers) these macros are defined as:

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

If BOOST_NO_CXX11_NOEXCEPT is not defined (i.e. C++11 compliant compilers) they are defined as:

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

Many of the other answers here have a similar implementation but this library is cleaner, better tested, and will do the right thing when your compiler is upgraded. I recommend looking at the boost config library in general for other features, especially in this time of language flux and varying levels of support among compilers.

3
votes

The noexcept is one of the easiest "lacks" of MSVC to deal with: Just use the macro _NOEXCEPT which under MSVC2013 is defined in yvals.h .

3
votes

Add the following lines in your code in Visual Studio:

#ifdef _NOEXCEPT
#define noexcept _NOEXCEPT
#endif
2
votes

What I've recently used is following:

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

and then just use NOEXCEPT everywhere.

1
votes

It seems that the old throw() (deprecated in C++11) works in both compilers. So I changed the code to:

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

The other way to go around is create header file and include it if necessary in your source code that should be compile by gcc, vc,or 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> doesn't cover case noexcept(false) but works fine for VC2010,2012,2013, gcc 4.9

0
votes

#IFs may work, even if a bit hacky.

You could just do this:

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

add the below path to the additional include directories

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

at this location there is file called "yvals.h" which contain definition of _NOEXCEPT