Как бороться с noexcept в Visual Studio

Я пытаюсь создать собственное исключение, которое происходит от 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, но не компилируется в GCC 4.8 с -std=c++11:

ошибка: более слабый спецификатор броска для «виртуального константного символа * UserException :: what () const»

Итак, я добавляю noexcept:

virtual const char* what() const noexcept override

Это хорошо работает в GCC, но не компилируется в Visual Studio (потому что VS 2012 не поддерживает noexcept):

ошибка C3646: «noexcept»: неизвестный спецификатор переопределения

Каков рекомендуемый способ борьбы с этим? Я хочу, чтобы один и тот же код компилировался с обоими компиляторами, и я использую функции C ++ 11, поэтому я не могу компилировать с разными -std,

43

Решение

Использовать макрос

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

А затем определить функцию как

virtual const char* what() const NOEXCEPT override

Вы также можете изменить это, чтобы noexcept в более поздних версиях VS, проверив значение _MSC_VER; для VS2012 значение составляет 1600.

43

Другие решения

«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
15

Эта проверка работает, чтобы увидеть, если 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.

12

использование BOOST_NOEXCEPT в <boost/config.hpp>

Библиотека config config была разработана для таких проблем совместимости. В соответствии с документ:

Если 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 config для других функций, особенно в это время языкового потока и различных уровней поддержки среди компиляторов.

9

noexcept Это один из самых простых недостатков MSVC: просто используйте макрос _NOEXCEPT который в MSVC2013 определен в yvals.h.

3

Добавьте следующие строки в ваш код в Visual Studio:

#ifdef _NOEXCEPT
#define noexcept _NOEXCEPT
#endif
3

Я недавно использовал следующее:

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

а потом просто использовать NOEXCEPT везде.

2

Кажется, что старый throw() (устарело в C ++ 11) работает в обоих компиляторах. Поэтому я изменил код на:

virtual const char* what() const throw() override
1
По вопросам рекламы [email protected]