48

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.

svick
  • 236,525
  • 50
  • 385
  • 514

11 Answers11

45

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.

Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • 2
    According to [this video (look at the table at 58:00)](http://channel9.msdn.com/Events/Build/2013/2-306), `noexcept` won't be supported in VS2013. – svick Aug 22 '13 at 18:32
  • 2
    Also, does it make sense to use `#define NOEXCEPT throw()` for the VS version? – svick Aug 22 '13 at 18:34
  • 2
    @svick There is a small difference in behavior between the two. Throwing from a function marked `throw()` will call `std::unexpected`, whereas `std::terminate` will be called if it were marked `noexcept`; but in your use case the two should be equivalent. However, the [MSDN page for `std::exception`](http://msdn.microsoft.com/en-us/library/c4ts6d5a.aspx) doesn't indicate `what()` is marked `throw()`, so you may run into warnings or errors if you add the exception specification to the overriden function. – Praetorian Aug 22 '13 at 18:45
16

"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
ivan.ukr
  • 2,853
  • 1
  • 23
  • 41
12

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.

marton78
  • 3,899
  • 2
  • 27
  • 38
  • Well, MSVC 2010 doesn't have `noexcept`, does it? Its `_MSC_VER` is `1600`, which is smaller than `1800`, therefore `NOEXCEPT` should expand to nothing. What is the problem you are experiencing? – marton78 Jun 25 '15 at 16:25
  • `warning C4067: unexpected tokens following preprocessor directive - expected a newline`. It looks like ` __has_feature(cxx_noexcept)` is confusing it for some reason. When I remove that it works fine. Edit: I realize now I was treating warnings as errors, and this was just a warning. If I suppress 4067 it works after all. – Alex Jun 25 '15 at 16:30
  • 180021114 seems to be VS2013, which does not support `noexcept`. ivan.ukr's value of 190023026 works better for me. – Emil Styrke Dec 22 '15 at 09:24
10

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.

svick
  • 236,525
  • 50
  • 385
  • 514
evan
  • 265
  • 2
  • 8
3

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 .

patlecat
  • 135
  • 7
  • 7
    But I wasn't looking for a solution that works only in VS, I was looking for a solution that works everywhere (or at least both in VS and GCC). – svick Apr 09 '14 at 17:45
  • 1
    **facepalm** Well @svick then use the macro I just gave you and combine it with the `noexcept` from C++11 and voilà you'll have a solution that works everywhere! :D – patlecat Jun 09 '14 at 13:18
3

Add the following lines in your code in Visual Studio:

#ifdef _NOEXCEPT
#define noexcept _NOEXCEPT
#endif
  • 2
    This is wrong. You are defining a macro with the same literal as a reserved keyword, which is forbidden. – StarShine Oct 30 '14 at 10:06
  • This works in VS to introduce compatibility between two versions. – Anant Simran Singh Nov 01 '14 at 08:12
  • Even in Visual Studio versions before C++11, noexcept is a reserved keyword. You'll get a warning during compilation. I suggest to use capital NOEXCEPT in this case. – StarShine Nov 02 '14 at 18:42
  • Wouldn't it be better to define _NOEXCEPT to noexcept if it's undefined? (So you'd use VS's version when compiling in MSVC and C++11's version in other compilers.) – idbrii Dec 16 '14 at 18:37
3

What I've recently used is following:

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

and then just use NOEXCEPT everywhere.

ivan.ukr
  • 2,853
  • 1
  • 23
  • 41
1

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
svick
  • 236,525
  • 50
  • 385
  • 514
  • 1
    But that is not the same thing. Does it remove the `looser throw specifier for ‘virtual const char* UserException::what() const’` error? – wilx Jan 17 '15 at 08:27
  • @VáclavZeman Yeah, as far as I remember, this actually worked for me. – svick Jan 17 '15 at 15:10
1

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

  • 1
    The advantage you can start use noexcept and after moving on VC 2015 just remove header in your code without impact: #include "no_except_work_around.h" – Alexei Valyaev Dec 01 '15 at 20:09
0

#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
It'sNotALie.
  • 22,289
  • 12
  • 68
  • 103
0

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

suraj kumar
  • 335
  • 1
  • 5