Gnu C++ macro __cplusplus standard conform? - c++

The Gnu C++ compiler seems to define __cplusplus to be 1
#include <iostream>
int main() {
std::cout << __cplusplus << std::endl;
}
This prints 1 with gcc in standard c++ mode, as well as in C++0x mode, with gcc 4.3.4, and gcc 4.7.0.
The C++11 FDIS says in "16.8 Predefined macro names [cpp.predefined]" that
The name __cplusplus is defined to the value 201103L when compiling a C++ translation unit. (Footnote: It is intended that future versions of this standard will replace the value of this macro with a greater value. Non-conforming com-
pilers should use a value with at most five decimal digits.)
The old std C++03 had a similar rule.
Is the GCC deliberatly setting this to 1, because it is "non-conforming"?
By reading through that list I thought that I could use __cplusplus to check in a portable way if I have a C++11 enabled compiler. But with g++ this does not seem to work. I know about the ...EXPERIMENTAL... macro, but got curious why g++ is defining __cplusplus this way.
My original problem was switch between different null-pointer-variants. Something like this:
#if __cplusplus > 201100L
# define MYNULL nullptr
#else
# define MYNULL NULL
#endif
Is there a simple and reasonably portable way to implement such a switch?

This was fixed about a month ago (for gcc 4.7.0). The bug report makes for an interesting read: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=1773

If I recall correctly this has to do with Solaris 8 causing issues when __cplusplus is set as it should. The gcc team decided at the time to support the Solaris 8 platform rather than be compliant in this particular clause. But I noticed that the latest version of gcc ends the Solaris 8 support, and I guess this is a first step in the right direction.

It is a very old g++ bug.
That is, the compiler is not conforming.
Apparently it can't be fixed because fixing it would break something on a crazy platform.
EDIT: oh, I see from #birryree's comment that has just been fixed, in version 4.7.0. So, it was not impossible to fix after all. Heh.
Cheers & hth.

Related

Is it possible to set g++ to follow C++11 ISO (-std=c++11) through #define?

I'm quite new to c++11 and I was wondering something...
I am using Code::Blocks and if I were to use c++11 in this IDE, i had to go to compiler settings, and and Check "Have g++ follow the C++11 ISO C++ language standard"
Is there any workaround so I can set a single .cpp file to use c++11 in the #define statement like this?
Note: This is a single "Build" file, NOT a project
By setting the compile option while not in project, it'll set it to Global Compile option that I prefer to not happen
I know that you can customize the build option in Project Files that It'll set c++11 for that project only
#include <iostream>
#define -std c++11
int main(){
#if __cplusplus==201402L
std::cout << "C++14" << std::endl;
#elif __cplusplus==201103L
std::cout << "C++11" << std::endl;
#else
std::cout << "C++" << std::endl;
#endif
return 0;
}
What I have found:
Changing #define __cplusplus 201103L is NOT a good idea, because it don't set the compiler to compile as c++11
Although I can see how it would be desirable for a source file to be self-documenting in this respect, this isn't possible.
The next best thing is to test conformance, as you've started to do:
#if __cplusplus < 201103L
#error This source must be compiled as C++11 or later
#endif
That ensures that compilation with a C++03 compiler will give a simple, understandable error message straight away.
Is it possible to set g++ to follow C++11 ISO (-std=c++11) through #define?
No.
Neither C++ nor g++ have that feature. You might want to build simple one-file programs manually.
No.
You shouldn't changing the #define __cplusplus. Read more in How to trigger the __cplusplus (C++) #ifdef?, because __cplusplus should be automatically defined by C++ compiler. That's why changing the version is meant to be done via the compiler settings.
It doesn't make sense to have a file follow C++11, while the others would follow C++14, for example. The whole project should be compiled in a homogeneous way.
Notice that your code wouldn't compile: Error: macro names must be identifiers using #ifdef 0.
PS: What a nightmare it would be in terms of readability and maintenance if what you described was a good idea..

Is #error directive crossplatform and crosscompiler

I know that #error directive works at least with GCC and MSVC
#if !defined(__cplusplus)
#error C++ compiler required.
#endif
But is it crossplatform and crosscompiler in general? Is it a part of some standard maybe?
PS. Because even looking at examples given in GCC and MSVC manuals one sees differences. While it works both with quotes or not, it makes a sad feeling, that it might be somehow compiler dependent.
GCC example
#error "Won't work on ..." // quotes here
MSVC example
#error C++ compiler required. // no qutes
Yes it is. It's a standard preprocessor directive in C and C++.
References:
http://en.cppreference.com/w/cpp/preprocessor/error
http://en.cppreference.com/w/c/preprocessor/error

What is the value of __cplusplus for C++17?

We are trying to test some code under C++17 and its change to std::uncaught_exception. I can't seem to get GCC to provide the value of __cplusplus:
$ /opt/local/bin/g++ -std=c++17 -dM -E - </dev/null | grep __cplusplus
cc1: warning: command line option '-std=c++1z' is valid for C++/ObjC++ but not for C
$
And:
$ /opt/local/bin/g++ --version
g++-mp-6 (MacPorts gcc6 6.1.0_0) 6.1.0
Copyright (C) 2016 Free Software Foundation, Inc.
What is the value of __cplusplus when using C++17?
tl;dr: For C++17, __cplusplus is 201703L.
What is the value of __cplusplus when using C++17?
According to the draft standard N4594 §16.8/p1 Predefined macro names [cpp.predefined] (Emphasis Mine):
The following macro names shall be defined by the implementation:
__cplusplus The name __cplusplus is defined to the value
201402L when compiling a C++ translation unit.156
156) 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.
However the same value is appointed for the C++14 standard. Apparently it seems so, that there's no official/standard __cplusplus value set yet for the C++17 standard.
In GCC versions 6.1 and 7.0 the value is changed to 201500
Live Demo
In Clang version 3.8 and 3.9 the value is unchanged 201406.
Consequently, you'll have to wait a little bit for the standard value to come out.
--- Update ---
According to the C++ standard §19.8/p1 Predefined macro names [cpp.predefined] (Emphasis Mine):
1 The following macro names shall be defined by the
implementation:
__cplusplus The integer literal 201703L.
Thus, the value of __cplusplus when using C++17 shall be 201703L.
I would try:
#if __cplusplus > 201402L
// C++14 code here
...
#endif
In other words, testing for greater than C++14 should work as compilers add more features. As someone mentioned above, GCC uses 201500L. It looks like clang uses 201406L (four months after C++14 I guess).
Using the above snippet should be cross-platform and will work even when C++17 comes out with real value for __cplusplus. For more details about evolving features try the feature test macros.
Normally you should use __cplusplus define to detect c++17, but by default microsoft compiler does not define that macro properly, see https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ - you need to either modify project settings to include /Zc:__cplusplus switch, or you could use syntax like this:
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
//C++17 specific stuff here
#endif
I realize you asked this question citing the Gnu C++ compiler as the one you're using, but you may want to have some awareness of what happens on the Visual C++ compiler, and strictly speaking, your question didn't ask about a specific compiler.
Currently, as of the date of this posting, the VC++ 2017 compiler sets __cplusplus to 199711L rather than what you might expect if you set the compiler to use c++17.
To get it to report correctly, you have to also set /Zc:__cplusplus.
(source: https://learn.microsoft.com/en-us/cpp/build/reference/zc-cplusplus?view=vs-2017 )
As to why? Well... in their words:
We tried updating the macro by default and discovered that a lot of
code doesn’t compile correctly when we change the value of
__cplusplus.
(source: https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/)
I don't really know why __cplusplus doesn't show up as a regular macro, but I'm guessing it's so you can't redefine it. This is how I determine the its value.
#include <iostream>
int main( int argc, char** argv )
{
std::cout << __cplusplus << std::endl;
return 0;
}
Then compilation shows the value.
$ g++-6 test.cpp && ./a.out
201402
$ g++-6 -std=c++17 test.cpp && ./a.out
201500
I would check whether it's >= 201500 as opposed to checking for any specific value.
A modern compile time check that you can put in any file that needs it:
static_assert(__cplusplus >= 201703L, "This file expects a C++17 compatible compiler.");

How do I test the version of libstdc++, not GCC, at compile time?

I am trying to test the version of libstdc++ because std::regex is implemented, but largely broken, in the versions of libstdc++ distributed with GCC before version 4.9.0.
Note that:
I need to test the version of libstdc++, not GCC because Clang also supports using libstdc++ as the standard library. This rules out testing the __GNUC_PATCHLEVEL__, __GNUC__, and __GNUC_MINOR__ macros.
The __GLIBCXX__ macro is a date, not a version number and does not increase monotonically. For example, GCC 4.8.4 ships with #define __GLIBCXX__ 20150426, which is newer than the release date of GCC 4.9.0.
Is there any portable way to test the version of libstdc++ that does not depend on using GCC my compiler?
In my opinion the problem is sufficiently small to be solved by brute force.
In a header file called machine.hpp or similar I would test that the version of the C++ Standard is at least what I need it to be (the __cplusplus macro). Then I would add the various macro checks to reject any library that I know to be flawed.
In other words, I would take a black-list approach instead of a white-list approach.
For example:
#pragma once
#ifndef MACHINE_HPP_HEADER_GUARDS
#define MACHINE_HPP_HEADER_GUARDS
#if __cplusplus < 201103L
// Library is incompatible if it does not implement at least the C++11
// standard.
#error "I need a library that supports at least C++11."
#else
// Load an arbitrary header to ensure that the pre-processor macro is
// defined. Otherwise you will need to load this header AFTER you
// #include the header you care about.
#include <iosfwd>
#endif
#if __GLIBCXX__ == 20150422
#error "This version of GLIBCXX (20150422) has flaws in it"
#endif
// ...repeat for other versions of GLIBCXX that you know to be flawed
#endif // MACHINE_HPP_HEADER_GUARDS

Detect ICC vs GCC at compile time

How to detect at compile time if I'm using gcc or icc?
(I was quite puzzled to find out that icc defines __GNUC__ -- and even __GNUC_MINOR__ and __GNUC_PATCHLEVEL__ ! why?)
We use
#ifdef __INTEL_COMPILER
to split icc off, assuming gcc as a default.
I believe you could check for __INTEL_COMPILER according to this.
The reason ICC defines __GNUC__ etc. is because of code like yours that is inspecting compiler-specific macros and expects to see them...
Traditionally, compilers have defined a symbol of their own as well as their version as preprocessor symbols so that the code could be adapted (generally to work around bugs or specificities).
CLang has introduced a mechanism I had not seen so far, under the form of the __has_feature query. It does not replace the "work around bugs" practices (which is why CLang still exposes specific symbols) but allows a more natural style for querying the compiler capacities. I don't know if other compilers plan on defining such a facility.
You can make the processor output the defined macros in the preprocessor output and look for a macro that suits you. You can generated the preprocessor output like this:
icc -dM -E -o foo.P foo.c
Then look at foo.P (since it is a text file). In my case, I found icc defined an __ICC macro with the version of the compiler. It didn't define any __INTEL_COMPILER though.