4

I'm working with a C++ library. The library's minimum requirements are C++03. I'm catching some warnings under Visual Studio 2015 regarding throwing destructors:

... algparam.h(271): warning C4297: 'AlgorithmParametersBase::~AlgorithmParametersBase':
    function assumed not to throw an exception but does
... algparam.h(271): note: destructor or deallocator has
    a (possibly implicit) non-throwing exception specification

The throw was by design in the 1990s when the code was written, but its showing its age now. We are kind of boxed in at the moment because we are not ready for a major version bump. (And its not as bad as it sounds prima fascia because it guards the throw based on uncaught_exception).

I want to remediate the issue by detecting C++ 11, and then adding noexcept(false). I was going to hide it in a macro so the code would compile under both C++03 and C++11.

The following does not work to detect C++11 under Visual Studio 2015. It does not produce the expected compiler error:

#if (__cpluplus >= 201103L)
# error Not C++11
#endif

Additionally, Microsoft does not appear to offer a Predefined Macros for detection of the language features.

How do I detect C++11 under Visual Studio 2015?


Related, I can detect the version of MSVC compiler via _MSC_VER. I think it will be _MSC_VER=1900 for VS2015. But it does not tell me anything about the language features.

Language features are important if the user enlists VS2015, but uses a downlevel C++ standard. Also, I don't have VS2013 to test, so I'm not sure a 1-off string like _MSC_VER=1700 is a good idea. I'd much rather learn if its C++11 or not.


I've run into similar issues on OS X and Linux with Clang and GCC compilers. See, for example, How to guard move constructors for C++03 and C++11? and What differences, if any, between C++03 and C++11 can be detected at run-time? But in this case, I want to detect it via the preprocessor.


Finally, this library does not use Autotools, Cmake or Boost. It has no external dependencies.

Community
  • 1
  • 1
jww
  • 97,681
  • 90
  • 411
  • 885
  • 3
    More generally, throwing destructors are banned by the stdlib and possibly by the language in a huge number of cases. I'd seriously review any throwing destructor and spend some time re-thinking that, as the number of problems it could, well, throw, your way are enormous. – Puppy Jul 26 '15 at 22:15
  • @Puppy - yeah, we are paying for past sins. Its one throwing destructor, and its by design (out of literally hundreds of classes). It looks like we are going to have to accommodate past behavior until we can perform a minor or major version bump of the library. – jww Jul 26 '15 at 22:21
  • You say that this is by design... Your design isn't very safe, your destructor must destruct, if flow control leaves then you can't guarantee full destruction, and if that destructor were to be triggered from an exception you will be in UB( most implimentations put the current exception into a single register so you could end up returning to the wrong address even if it doesn't crash) ... So even if what you are doing is all technically legal, it seems pretty smelly – Grady Player Jul 26 '15 at 22:22
  • @Grady - this surfaced in the early 1990s, long before the guarantees you are talking about were specified, adopted as best practices and codified. No one claims its a good design. Its what we have to work with. Like I said, we are paying for past sins. – jww Jul 26 '15 at 22:24

1 Answers1

6

You can't detect the language version independently of the VS version, because VS does not offer language versioning switches- there's no such thing as VS2015 C++03 mode. The condition you're trying to detect (a downlevel standard with VS2015) does not exist, which handily explains why there is no feature macro to detect it.

Simply detect the VS version and switch off that.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • 3
    @jww: There's a Microsoft feature matrix... somewhere. But it's not very reliable as a lot of the advertised features are too buggy to be really reliable. However, I can definitively tell you that versions prior to 2015 do not support noexcept. – Puppy Jul 26 '15 at 22:29
  • I don't think Microsoft have more than the one C++11 compiler? – Jonathan Potter Jul 26 '15 at 22:30
  • 1
    Most recent feature matrix is here: http://blogs.msdn.com/b/vcblog/archive/2015/06/19/c-11-14-17-features-in-vs-2015-rtm.aspx – Jonathan Potter Jul 26 '15 at 22:32
  • `__cplusplus` expands to `199711` in MSVC C++ compiles regardless of version since at least VS2003 (in VC6 it expands to `1`). There is probably some lame compatibility reason for that. So yes, you'll need to test the MSVC version using something like `_MSC_VER` – Michael Burr Jul 26 '15 at 23:13
  • 1
    This is true for any compiler, not only MSVC. One can check if a **feature** is supported based on a compiler version and sometimes additional macros. With MSVC `_MSC_FULL_VER` should probably be used for better precision, not `_MSC_VER`, with clang `__has_feature()`, with GCC `__GNUC__`, `__GNUC_MINOR__` and `__GXX_EXPERIMENTAL_CXX0X__`, `__GNUC_PATCHLEVEL__` if needed. – Adam Wulkiewicz Jul 27 '15 at 14:22
  • Newer and more readable feature matrix https://msdn.microsoft.com/en-us/library/hh567368.aspx – user7610 Oct 17 '17 at 14:56