Как справиться с noexcept в Visual Studio
Я пытаюсь создать пользовательское исключение, которое вытекает из std::exception и переопределяет what(). Сначала я написал так:--9-->
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:
ошибка: более свободный спецификатор броска для ' 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.
10 ответов
использовать макрос
#ifndef _MSC_VER
#define NOEXCEPT noexcept
#else
#define NOEXCEPT
#endif
а затем определите функцию как
virtual const char* what() const NOEXCEPT override
вы также можете изменить, чтобы разрешить noexcept в более поздних версиях VS, проверив значение _MSC_VER; для VS2012 значение равно 1600.
"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
это проверить, работает ли 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.
использовать BOOST_NOEXCEPT на <boost/config.hpp>
библиотека конфигурации boost была разработана для таких проблем совместимости. Согласно док:
если
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 в целом для других функций, особенно в это время языкового потока и различных уровней поддержки среди компиляторов.
на noexcept является одним из самых простых "недостатков" MSVC: просто используйте макрос _NOEXCEPT который под MSVC2013 определен в yvals.ч.
то, что я недавно использовал, следующее:
#ifdef _MSC_VER
#define NOEXCEPT _NOEXCEPT
#else
#define NOEXCEPT noexcept
#endif
а затем просто используйте NOEXCEPT везде.
Кажется, что старый throw() (устаревший в C++11) работает в обоих компиляторах. Поэтому я изменил код на:
virtual const char* what() const throw() override
другой способ обойти-создать файл заголовка и при необходимости включить его в исходный код, который должен быть скомпилирован 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
=====================================================
П. С.> Не чехол как noexcept(ложные) но отлично работает для VC2010, 2012, 2013, gcc 4.9
#IFS может работать, даже если немного суховато.
вы могли бы просто сделать это:
#if __GNUG__
virtual const char* what() const noexcept override
#else
virtual const char* what() const override
#endif
//method body