diff --git a/include/wx/defs.h b/include/wx/defs.h index a6f65574c7..7199c59ac6 100644 --- a/include/wx/defs.h +++ b/include/wx/defs.h @@ -216,6 +216,24 @@ #define __USE_W32_SOCKETS #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 */ /* ---------------------------------------------------------------------------- */ @@ -302,7 +320,7 @@ typedef short int WXTYPE; /* 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]] #elif __cplusplus >= 201103L && defined(__has_warning) && WX_HAS_CLANG_FEATURE(cxx_attributes) #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 without the warnings. */ -#if defined(__cplusplus) && (__cplusplus >= 202002L) +#if wxCHECK_CXX_STD(202002L) #define wxALLOW_COMBINING_ENUMS_IMPL(en1, en2) \ inline int operator|(en1 v1, en2 v2) \ { return static_cast(v1) | static_cast(v2); } \ diff --git a/include/wx/event.h b/include/wx/event.h index 5e58938644..dbda32ee6c 100644 --- a/include/wx/event.h +++ b/include/wx/event.h @@ -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 // handler is a noexcept function, so we need to cast it to a noexcept function // pointer first. -#if __cplusplus >= 201703L +#if wxCHECK_CXX_STD(201703L) namespace wxPrivate { diff --git a/include/wx/math.h b/include/wx/math.h index 8a20d9ee55..fd76129881 100644 --- a/include/wx/math.h +++ b/include/wx/math.h @@ -59,7 +59,7 @@ 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. */ -#if __cplusplus >= 201103 +#if wxCHECK_CXX_STD(201103) #define wxFinite(x) std::isfinite(x) #define wxIsNaN(x) std::isnan(x) #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, "argument out of supported range"); - #if __cplusplus >= 201103 + #if wxCHECK_CXX_STD(201103) return int(std::lround(x)); #elif defined(HAVE_ROUND) || wxCHECK_VISUALC_VERSION(12) return int(lround(x)); @@ -153,7 +153,7 @@ inline int wxRound(float x) wxASSERT_MSG(x > float(INT_MIN) && x < float(INT_MAX), "argument out of supported range"); - #if __cplusplus >= 201103 + #if wxCHECK_CXX_STD(201103) return int(std::lround(x)); #elif defined(HAVE_ROUND) || wxCHECK_VISUALC_VERSION(12) return int(lroundf(x)); diff --git a/include/wx/wxcrtbase.h b/include/wx/wxcrtbase.h index f52a543d91..8545bad304 100644 --- a/include/wx/wxcrtbase.h +++ b/include/wx/wxcrtbase.h @@ -180,7 +180,7 @@ extern unsigned long android_wcstoul(const wchar_t *nptr, wchar_t **endptr, int #define wxCRT_StrtoullW _wcstoui64 #else /* Both of these functions are implemented in C++11 compilers */ - #if defined(__cplusplus) && __cplusplus >= 201103L + #if wxCHECK_CXX_STD(201103L) #ifndef HAVE_STRTOULL #define HAVE_STRTOULL #endif diff --git a/interface/wx/defs.h b/interface/wx/defs.h index 96fdf72a8c..b33974fdc3 100644 --- a/interface/wx/defs.h +++ b/interface/wx/defs.h @@ -1516,6 +1516,26 @@ typedef double wxDouble; /** @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 default assignment operator. diff --git a/tests/test.cpp b/tests/test.cpp index 03636da8f3..90be379f97 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -133,7 +133,7 @@ static void TestAssertHandler(const wxString& file, // so we'd just die without any useful information -- abort instead. 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 else if ( uncaught_exception() )