__cplusplus expanded minimum values - c++

Am I right to understand that these are the minimum values of __cplusplus and that C++98 has the same value has C++03?
// C++ 98
#define __cplusplus 199711L
// C++ 03
#define __cplusplus 199711L
// C++ 11
#define __cplusplus 201103L
// C++ 14
#define __cplusplus 201402L
// C++ 17
#define __cplusplus 201500L
// C++ 20
#define __cplusplus 201704L
// looks like the format is YEAR*100+something
Also, does C++20 have an official value now that the standard is released?

Also, does C++20 have an official value now that the standard is released?
It does: 202002L. The format here is a date: YYYYMM (C++20 was made official in February 2020). The value for C++17 was 201703L, not 201500. All the rest are correct (C++03 did not change the __cplusplus macro).
However, this macro is far too coarse to be generally useful. Implementations don't just add every feature in one go, they get added as time progresses. So you're better off using feature-test macros to test for what you actually need.

Related

undefine and redefine the __cplusplus macro

I want to undefine and redefine the __cplusplus macro am getting however compilation error:__cplusplus was not declared in this scope
#define TEMP_VERSION __cplusplus // temporary macro to hold the __cplusplus containt
#undef __cplusplus
#define __cplusplus TEMP_VERSION // redefine __cplusplus
#define AA 111
#undef AA
#define AA 111
int main()
{
cout << "__cplusplus = "<<__cplusplus<<endl; // It doesn't work
cout << "AA = "<<AA<<endl; // It works
return 0;
}
Question 1: Why it is not working with the __cplusplus but works with AA
I know that this is really ugly but the reason why am undefining the macro is that I am using a third party Software where they are missusing the #ifdef __cplusplus, I mean the content of the #ifdef __cplusplus ... #endif is wrong. So instead of changing their software I choosed to do the following
#define TEMP_VERSION __cplusplus
#undef __cplusplus
#include <third_party_sw.h>
#define __cplusplus TEMP_VERSION
Question 2: What do you think is it a good approach ?
From the C++ standard ([cpp.predefined, 3-4]):
The values of the predefined macros (except for __FILE__ and __LINE__)
remain constant throughout the translation unit. If any of the
pre-defined macro names in this subclause, or the identifier defined,
is the subject of a #define or a #undef preprocessing directive, the
behavior is undefined.
In other words, the __cplusplus macro isn't just something that the compiler starts out by defining before handing control over to you; it is an immutable constant, which cannot be changed and is an error to attempt to change.
As for whether it would be a good approach if it were possible: Depends on the context, but probably not. These sorts of "fool the header" hacks (#define private public, anyone?) are seldom effective and never safe.
EDIT: Oh, also incidentally, even if you did have a macro it was legal to save/restore, that wouldn't be the right way to do it. See Can I redefine a C++ macro then define it back?.
Question 1: Why it is not working with the __cplusplus but works with AA
Because __cplusplus is a pre-defined macro, and behaviour of (un-)defining it is undefined:
stadard draft [cpp.predefined]
If any of the pre-defined macro names in this subclause, or the identifier defined, is the subject of a #define or a #undef preprocessing directive, the behavior is undefined. ...
AA is not a pre-defined macro, nor is the indentifier reserved. It is OK to (re-)define it.
Question 2: What do you think is it a good approach ?
(Re-)defining reserved identifiers is never a good approach. Even redefining user defined macros is a dubious proposition.
Ideal approach might be to fix the third party software, if possible. Alternatively, you could write a custom header for the software which doesn't have the problem.
It's because __cplusplus is pre-defined by the compiler.
Technically, it's the pre-processor that defines them, but depending on which compiler invokes the pre-processor, the output may differ. Try running this:
$ g++ -dM -E - </dev/null
The output is all the pre-processor defines that (in this case) the pre-processor run by this command produces.
Mind you __cplusplus does not appear there. It's built-in for every C++ compilation unit.
(The same works when substituting clang++ for g++.)

What does the "__cplusplus" macro expand to?

What does the C++ macro __cplusplus contain and expand to?
Does the macro __cplusplus always, even in oldest C++ implementation, contain and expand to a numeric value?
Is it safe to use #if __cplusplus
or should we use instead of that #ifdef __cplusplus?
Conclusion (added later)
From comments and accepted answer:
__cplusplus expands to a number representing the standard's version, except pre-standard C++ in the early 90s (which simply expanded to 1).
Yes, even in oldest C++ implementation (expands to a numeric value).
No, #ifdef should be used when header is shared with C-language (because some C-compilers will warn when #if checks undefined macro).
Yes, it always does expand to numeric value and its meaning is the version of C++ standard that is being used. According to cppreference page, __cplusplus macro should expand to:
199711L (until C++11),
201103L (C++11),
201402L (C++14),
201703L (C++17),
202002L (C++20)
The difference between #if and #ifdef directives is that #ifdef should be used to check whether given macro has been defined to allow a section of code to be compiled.
On the other hand #if (#else, #elif) directives can be used to check whether specified condition is met (just like typical if-condition).
__cplusplus is required to be defined by the C++ standard. For C++11 or higher __cplusplus > 199711L should hold true.
Does the macro __cplusplus always, even in oldest C++ implementation,
contain and expand to a numeric value?
Yes it does.
19.8 C++11
__cplusplus
The integer literal 201703L. [ Note: It is intended that future
versions of this International Standard will replace the value of this
macro with a greater value. — end note  ]
C++98
__cplusplus The name
_
_cplusplus is defined to the value 199711L when compiling a C
++ translation unit. 143)
Unfortunately, the __cplusplus macro has the value 199711 in MS Visual Studio 2022, regardless of the specified C++ standard. Use _MSVC_LANG instead. See VS comment.
This seems to work:
#if defined(_MSVC_LANG) // MS compiler has different __cplusplus value.
# if _MSVC_LANG < 201703
# error Please compile for C++17 or higher
# endif
#else // All other compilers.
# if __cplusplus < 201703
# error Please compile for C++17 or higher
# endif
#endif

Can __cplusplus ever be defined and equal to zero? [duplicate]

This question already has answers here:
How are the __cplusplus directive defined in various compilers?
(4 answers)
Closed 5 years ago.
The question came up of whether one should wrap extern "C" using #if or #ifdef. i.e.:
#if __cplusplus
extern "C" {
#endif
or
#ifdef __cplusplus
extern "C" {
#endif
Which begs the question: is there ever a situation where __cplusplus is defined to be equal to zero?
According to the standard, the __cplusplus macro must be defined, the exact definition depends on the C++ standard being used but it will not be zero.
For example, for C++11 it must be 201103L, with the note "It is intended that future versions of this standard will replace the value of this macro with a greater value."
Historically, in some ancient non-conforming compilers you could probably dig up, __cplusplus was defined to 0 to indicate non-conformance with the standard. This is only of historical interest.
See: How are the __cplusplus directive defined in various compilers?

How to assert that C++11 should be used to compile my program?

I want to use some C++11 features in my program. I might have to share my source code with others in future. How do I assert, inside the code, that C++11 should be used to compile my program? An older compiler might throw an error, but I want the user to be informed clearly that C++11 is required.
I'm using the following C++11 features, if that matters:
enum with storage size specified
std shared pointer
thanks
You could check that the value of the __cplusplus macro is 201103L or greater:
#if __cplusplus < 201103L
#error This code requires C++11
#endif
C++11 16.8 Predefined macro names:
The following macro names shall be defined by the implementation:
__cplusplus
The name __cplusplus is defined to the value 201103L when compiling a C++ translation unit. (155)
(155) It is intended that future versions of this standard will replace the value of this macro with a greater value. Non-conforming
compilers should use a value with at most five decimal digits.
__cplusplus macro may come handy
#if __cplusplus < 201103L
#error C++11 Required
#endif
Something like this
As it has already been said, the correct solution would be to check for the __cplusplus macro. However, some compilers have a partial support for C++11 features but do not set this macro for the correct value. For example, strongly-typed enumerations are available in g++ since GCC 4.4.0. However, with the option -std=c++11 (and its equivalents), the macro __cplusplus was not set to the good value before GCC 4.7.0 (it was set to 1 instead). That means that some compilers can compile your code but won't if you check for C++11 that way.
If you just need specific features, then I would check for them with Boost.Config which defines a whole set of macros that can be used to check whther your compiler supports the required features. In your case, you would need:
BOOST_NO_CXX11_SCOPED_ENUMS for strongly-typed enumerations.
BOOST_NO_CXX11_SMART_PTR for std::shared_ptr.

How to trigger the __cplusplus (C++) #ifdef?

#ifdef __cplusplus
// C++ code
#else
// C code
#endif
The structure is this.
My question is, how to actually trigger the #ifdef on?
I mean, in program? What code I write can turn #ifdef on?
For example, in this case.
is that
#define __cplusplus
will turn it on?
"#define __cplusplus"
will let it on?
Yes, it will "let it on".
__cplusplus should be automatically defined by C++ compiler. C++ uses different name mangling and the macro often used to make C headers compatible with C++:
#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
}
#endif
Just compile it with a C++ compiler and __cplusplus is defined automatically in that case.
The C++ Standard enforces that __cplusplus will always be defined in C++ programs. The C Standard obviously does not. This means that the user need go to no effort to enable this machinery.
A C++ compiler defines this automatically.
Since this starts with two consecutive underscores, it is reserved. You are not allowed to define it yourself (i.e., attempting to do so gives undefined behavior).