Add wxCHECK_CXX_STD() and use it to test for C++17 and C++20

Unlike direct tests of __cplusplus, using this macro also works with
(recent enough, i.e. MSVS 2015.3 or later) MSVC versions, even if
/Zc:__cplusplus is not used.

This simplifies some checks and makes some other ones (notably the check
for C++20 used before wxALLOW_COMBINING_ENUMS macro definition) work
with MSVC versions with C++20 support as intended.
This commit is contained in:
Vadim Zeitlin
2022-05-11 16:57:18 +01:00
parent d311a07b7a
commit 2ba9007d0e
6 changed files with 46 additions and 8 deletions

View File

@@ -216,6 +216,24 @@
#define __USE_W32_SOCKETS #define __USE_W32_SOCKETS
#endif #endif
#if defined(_MSVC_LANG)
/*
We want to always use the really supported C++ standard when using MSVC
recent enough to define _MSVC_LANG, even if /Zc:__cplusplus option is not
used, but unfortunately we can't just redefine __cplusplus as _MSVC_LANG
because this is not allowed by the standard and, worse, doesn't work in
practice (it results in a warning and nothing else).
So, instead, we define a macro for testing __cplusplus which also works in
this case.
*/
#define wxCHECK_CXX_STD(ver) (_MSVC_LANG >= (ver))
#elif defined(__cplusplus)
#define wxCHECK_CXX_STD(ver) (__cplusplus >= (ver))
#else
#define wxCHECK_CXX_STD(ver) 0
#endif
/* ---------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------- */
/* check for native bool type and TRUE/FALSE constants */ /* check for native bool type and TRUE/FALSE constants */
/* ---------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------- */
@@ -302,7 +320,7 @@ typedef short int WXTYPE;
/* wxFALLTHROUGH is used to notate explicit fallthroughs in switch statements */ /* wxFALLTHROUGH is used to notate explicit fallthroughs in switch statements */
#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) #if wxCHECK_CXX_STD(201703L)
#define wxFALLTHROUGH [[fallthrough]] #define wxFALLTHROUGH [[fallthrough]]
#elif __cplusplus >= 201103L && defined(__has_warning) && WX_HAS_CLANG_FEATURE(cxx_attributes) #elif __cplusplus >= 201103L && defined(__has_warning) && WX_HAS_CLANG_FEATURE(cxx_attributes)
#define wxFALLTHROUGH [[clang::fallthrough]] #define wxFALLTHROUGH [[clang::fallthrough]]
@@ -1303,7 +1321,7 @@ typedef double wxDouble;
for doing this, that do the same thing as would happen without them, but for doing this, that do the same thing as would happen without them, but
without the warnings. without the warnings.
*/ */
#if defined(__cplusplus) && (__cplusplus >= 202002L) #if wxCHECK_CXX_STD(202002L)
#define wxALLOW_COMBINING_ENUMS_IMPL(en1, en2) \ #define wxALLOW_COMBINING_ENUMS_IMPL(en1, en2) \
inline int operator|(en1 v1, en2 v2) \ inline int operator|(en1 v1, en2 v2) \
{ return static_cast<int>(v1) | static_cast<int>(v2); } \ { return static_cast<int>(v1) | static_cast<int>(v2); } \

View File

@@ -145,7 +145,7 @@ inline wxEventFunction wxEventFunctionCast(void (wxEvtHandler::*func)(T&))
// a type of wxEvtHandler method. But with C++17 this doesn't work when the // a type of wxEvtHandler method. But with C++17 this doesn't work when the
// handler is a noexcept function, so we need to cast it to a noexcept function // handler is a noexcept function, so we need to cast it to a noexcept function
// pointer first. // pointer first.
#if __cplusplus >= 201703L #if wxCHECK_CXX_STD(201703L)
namespace wxPrivate namespace wxPrivate
{ {

View File

@@ -59,7 +59,7 @@
Things are simple with C++11: we have everything we need in std. Things are simple with C++11: we have everything we need in std.
Eventually we will only have this section and not the legacy stuff below. Eventually we will only have this section and not the legacy stuff below.
*/ */
#if __cplusplus >= 201103 #if wxCHECK_CXX_STD(201103)
#define wxFinite(x) std::isfinite(x) #define wxFinite(x) std::isfinite(x)
#define wxIsNaN(x) std::isnan(x) #define wxIsNaN(x) std::isnan(x)
#else /* C++98 */ #else /* C++98 */
@@ -139,7 +139,7 @@ inline int wxRound(double x)
wxASSERT_MSG(x > double(INT_MIN) - 0.5 && x < double(INT_MAX) + 0.5, wxASSERT_MSG(x > double(INT_MIN) - 0.5 && x < double(INT_MAX) + 0.5,
"argument out of supported range"); "argument out of supported range");
#if __cplusplus >= 201103 #if wxCHECK_CXX_STD(201103)
return int(std::lround(x)); return int(std::lround(x));
#elif defined(HAVE_ROUND) || wxCHECK_VISUALC_VERSION(12) #elif defined(HAVE_ROUND) || wxCHECK_VISUALC_VERSION(12)
return int(lround(x)); return int(lround(x));
@@ -153,7 +153,7 @@ inline int wxRound(float x)
wxASSERT_MSG(x > float(INT_MIN) && x < float(INT_MAX), wxASSERT_MSG(x > float(INT_MIN) && x < float(INT_MAX),
"argument out of supported range"); "argument out of supported range");
#if __cplusplus >= 201103 #if wxCHECK_CXX_STD(201103)
return int(std::lround(x)); return int(std::lround(x));
#elif defined(HAVE_ROUND) || wxCHECK_VISUALC_VERSION(12) #elif defined(HAVE_ROUND) || wxCHECK_VISUALC_VERSION(12)
return int(lroundf(x)); return int(lroundf(x));

View File

@@ -180,7 +180,7 @@ extern unsigned long android_wcstoul(const wchar_t *nptr, wchar_t **endptr, int
#define wxCRT_StrtoullW _wcstoui64 #define wxCRT_StrtoullW _wcstoui64
#else #else
/* Both of these functions are implemented in C++11 compilers */ /* Both of these functions are implemented in C++11 compilers */
#if defined(__cplusplus) && __cplusplus >= 201103L #if wxCHECK_CXX_STD(201103L)
#ifndef HAVE_STRTOULL #ifndef HAVE_STRTOULL
#define HAVE_STRTOULL #define HAVE_STRTOULL
#endif #endif

View File

@@ -1516,6 +1516,26 @@ typedef double wxDouble;
/** @addtogroup group_funcmacro_misc */ /** @addtogroup group_funcmacro_misc */
//@{ //@{
/**
Returns @true if the compiler being used supports the given C++ version.
The @a stdver parameter uses the same values as the standard @c __cplusplus
macro, i.e.
- 201103L for C++11
- 201402L for C++14
- 201703L for C++17
- 202002L for C++20
Using this macro also works with MSVC, even when @c /Zc:__cplusplus option
is not used, unlike checking for the value of @c __cplusplus directly.
@since 3.1.7
@header{wx/defs.h}
*/
#define wxCHECK_CXX_STD(stdver)
/** /**
This macro can be used in a class declaration to disable the generation of This macro can be used in a class declaration to disable the generation of
default assignment operator. default assignment operator.

View File

@@ -133,7 +133,7 @@ static void TestAssertHandler(const wxString& file,
// so we'd just die without any useful information -- abort instead. // so we'd just die without any useful information -- abort instead.
abortReason << assertMessage << wxASCII_STR(" in a worker thread."); abortReason << assertMessage << wxASCII_STR(" in a worker thread.");
} }
#if __cplusplus >= 201703L || wxCHECK_VISUALC_VERSION(14) #if wxCHECK_CXX_STD(201703L)
else if ( uncaught_exceptions() ) else if ( uncaught_exceptions() )
#else #else
else if ( uncaught_exception() ) else if ( uncaught_exception() )