J'essaie de créer une exception personnalisée qui dérive de std::exception
et remplace what()
. Au début, je l’écrivais comme ceci:
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();
}
};
Cela fonctionne très bien dans VS2012, mais il ne compile pas dans GCC 4.8 avec -std=c++11
:
error: spécificateur de projection plus lâche pour 'virtual const char * UserException :: what () const'
J'ajoute donc noexcept
:
virtual const char* what() const noexcept override
Cela fonctionne bien dans GCC, mais il ne compile pas dans Visual Studio (car VS 2012 ne prend pas en charge noexcept
):
erreur C3646: 'noexcept': spécificateur de substitution inconnu
Quelle est la façon recommandée de gérer cela? Je veux que le même code soit compilé avec les deux compilateurs et que j'utilise les fonctionnalités de C++ 11. Je ne peux donc pas compiler avec un -std
différent.
Utilisez une macro
#ifndef _MSC_VER
#define NOEXCEPT noexcept
#else
#define NOEXCEPT
#endif
Et ensuite définir la fonction comme
virtual const char* what() const NOEXCEPT override
Vous pouvez également modifier cela pour autoriser noexcept
sur les versions ultérieures de VS en vérifiant la valeur de _MSC_VER
; pour VS2012, la valeur est 1600.
"noexcept" n'est pris en charge que depuis Visual Studio 2015 (comme indiqué ici: https://msdn.Microsoft.com/en-us/library/wfa0edys.aspx ) . J'ai utilisé le code suivant avec Visual Studio 2013 (dérivé des exemples ci-dessus):
#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
Cette vérification permet de voir si noexcept
est pris en charge:
// 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
Ce qui précède fonctionne avec Clang, GCC et MSVC.
utiliser BOOST_NOEXCEPT
dans <boost/config.hpp>
La bibliothèque de configuration boost a été conçue pour des problèmes de compatibilité tels que celui-ci. Selon le doc :
Si
BOOST_NO_CXX11_NOEXCEPT
est défini (c'est-à-dire des compilateurs conformes à C++ 03), ces macros sont définies comme suit:#define BOOST_NOEXCEPT #define BOOST_NOEXCEPT_OR_NOTHROW throw() #define BOOST_NOEXCEPT_IF(Predicate) #define BOOST_NOEXCEPT_EXPR(Expression) false
Si
BOOST_NO_CXX11_NOEXCEPT
n'est pas défini (c'est-à-dire des compilateurs conformes à C++ 11), ils sont définis comme suit:#define BOOST_NOEXCEPT noexcept #define BOOST_NOEXCEPT_OR_NOTHROW noexcept #define BOOST_NOEXCEPT_IF(Predicate) noexcept((Predicate)) #define BOOST_NOEXCEPT_EXPR(Expression) noexcept((Expression))
Beaucoup des autres réponses ici ont une implémentation similaire mais cette bibliothèque est plus propre, mieux testée et fera le bon choix lorsque votre compilateur sera mis à niveau. Je recommande de regarder la bibliothèque boost config en général pour d'autres fonctionnalités, en particulier en cette période de flux de langue et de niveaux de support variables parmi les compilateurs.
Le noexcept est l'un des "manques" les plus faciles à résoudre de MSVC: utilisez simplement la macro _NOEXCEPT
qui, sous MSVC2013, est définie dans yvals.h.
Ajoutez les lignes suivantes dans votre code dans Visual Studio:
#ifdef _NOEXCEPT
#define noexcept _NOEXCEPT
#endif
Ce que j'ai récemment utilisé est le suivant:
#ifdef _MSC_VER
#define NOEXCEPT _NOEXCEPT
#else
#define NOEXCEPT noexcept
#endif
et ensuite, utilisez simplement NOEXCEPT
partout.
Il semble que l'ancien throw()
(obsolète en C++ 11) fonctionne dans les deux compilateurs. J'ai donc changé le code en:
virtual const char* what() const throw() override
L'autre solution consiste à créer un fichier d'en-tête et à l'inclure si nécessaire dans votre code source, qui devrait être compilé par gcc, vc ou clang.
#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> ne couvre pas le cas Noexcept (false) Mais fonctionne bien pour VC2010,2012,2013, gcc 4.9
#IF
s peut fonctionner, même si c'est un peu hacky.
Vous pouvez simplement faire ceci:
#if __GNUG__
virtual const char* what() const noexcept override
#else
virtual const char* what() const override
#endif
//method body
ajoutez le chemin ci-dessous aux répertoires d'inclusion supplémentaires
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include
à cet emplacement, il y a un fichier appelé "yvals.h" qui contient la définition de _NOEXCEPT