Is it possible to compile a project with two different language standards? - c++

I have a project which is strictly written in C++14 and I want to use it in another project which is C++17. Some of the C++14 features like Dynamic Exception Specification were removed in C++17.
Is there any way to use and compile both code bases together? The project is large enough to make refactoring impractical.

This will be platform specific: It is conceivable that substantially different headers are selected according to the standard specified on the command line, etc.
That said, here is an answer from Jonathan Wakely which assures you that with gcc there should be no such problem, by design, if you keep away from unstable features in old compilers.
The underlying reason according to Jonathan is that C++ standard implementations in gcc, once declared stable, do not change their ABI (i.e, outward-facing type definitions, name mangling) with the selected C++ standard, not even between compiler versions.
Because all interaction between the translation units must be restricted to the smallest common standard version there is no issue: The C++11 features do not change if you specify C++17. Newer features in the C++17 TUs cannot be used for communication with earlier-standard TUs since they were not yet available, so no issue there either. If you are able to recompile, the safest advice would be:
Best to use the same std::string versions (which can be controlled from the command line at compile time).
Use the same libstdc++.
Use the same gcc version (and control the language standard used for each TU through the command line).
It would make sense for other compilers to follow a similar compatibility strategy.

Yes, you can detect the C++ version and compile conditionally:
void foo() {
#if __cplusplus >= 201703L
// code written for C++17 goes here
#else
// code written for C++14 goes here
#endif
}
The full list of __cplusplus macros is as follows:
#if __cplusplus >= 199711L // C++98
#if __cplusplus >= 201103L // C++11
#if __cplusplus >= 201402L // C++14
#if __cplusplus >= 201703L // C++17
#if __cplusplus >= 202002L // C++20
Note that this causes various problems:
it's impossible to test code like this unless you compile your tests for C++14 and C++17 separately
your IDE might not even show warnings or errors in removed preprocessed blocks
you need to maintain two separate version of the same code
So if you can, come up with a solution that works in both versions or at least use as few blocks like this as possible. If you just want a single keyword or so to be removed, then consider the following solution:
#if __cplusplus >= 201703L // C++17
#define THROWS(exception) noexcept(false)
#else
#define THROWS(exception) throw(exception)
#endif
// now you can use it like this in both C++14 and C++17:
void fun() THROWS(MyException);

Related

Macro for generalized lambda capture

I would like to use the generalized lambda capture introduced in C++14 (see Move capture in lambda for an explanation). However, the remainder of my code is C++11-friendly. I would like to do something along the lines of
#ifdef CPP14
// move capture in lambda
#else
// capture by-value
#endif
However, there are no good cross-compiler flags to infer versions. Is there anything anyone can suggest? (other than, of course, defining my own macros)
Actually T.C. is right, 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.
The footnote states:
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.
So going with the following code seems totally legit to me.
#if __cplusplus > 201103L
//c++1y or above
#else
//c++11 or below
#endif
However, some compiler might not follow the standard and you might want to check if the _cplusplus value has been incremented for c++1y.
The GCC, for example, had this flag set to 1 until the version 4.7.0.
If you need more information on the _cplusplus flag, you should take a look at this question

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.

A preprocessor #define to check for language version? C++98/C++03/C++11

Is there a preprocessor definition which I could use in #ifdef checks to discern the different versions of C++ language?
The value of the __cplusplus macro is supposed to serve this purpose. Unfortunately, GCC has (before 4.7) always set this to 1, making it unusable for this purpose.
(The values are 199711L for C++98/03, and 201103L for C++11.)

How to determine the version of the C++ standard used by the compiler?

How do you determine what version of the C++ standard is implemented by your compiler? As far as I know, below are the standards I've known:
C++03
C++98
From the Bjarne Stroustrup C++0x FAQ:
__cplusplus
In C++11 the macro __cplusplus will be set to a value that differs from (is greater than) the current 199711L.
Although this isn't as helpful as one would like. gcc (apparently for nearly 10 years) had this value set to 1, ruling out one major compiler, until it was fixed when gcc 4.7.0 came out.
MSVC also doesn't set this macro correctly, to this very day. By default it's defined to 199711L regardless of the language version, and you either need to add /Zc:__cplusplus to compiler flags, or check a MSVC-specific macro _MSVC_LANG instead, which always has the right value.
These are the C++ standards and what value you should be able to expect in __cplusplus:
C++ pre-C++98: __cplusplus is 1.
C++98: __cplusplus is 199711L.
C++98 + TR1: This reads as C++98 and there is no way to check that I know of.
C++11: __cplusplus is 201103L.
C++14: __cplusplus is 201402L.
C++17: __cplusplus is 201703L.
C++20: __cplusplus is 202002L.
If the compiler might be an older gcc, we need to resort to compiler specific hackery (look at a version macro, compare it to a table with implemented features) or use Boost.Config (which provides relevant macros). The advantage of this is that we actually can pick specific features of the new standard, and write a workaround if the feature is missing. This is often preferred over a wholesale solution, as some compilers will claim to implement C++11, but only offer a subset of the features.
The Stdcxx Wiki hosts a comprehensive matrix for compiler support of C++0x features (archive.org link) (if you dare to check for the features yourself).
Unfortunately, more finely-grained checking for features (e.g. individual library functions like std::copy_if) can only be done in the build system of your application (run code with the feature, check if it compiled and produced correct results - autoconf is the tool of choice if taking this route).
Please, run the following code to check the version.
#include<iostream>
int main() {
if (__cplusplus == 201703L) std::cout << "C++17\n";
else if (__cplusplus == 201402L) std::cout << "C++14\n";
else if (__cplusplus == 201103L) std::cout << "C++11\n";
else if (__cplusplus == 199711L) std::cout << "C++98\n";
else std::cout << "pre-standard C++\n";
}
By my knowledge there is no overall way to do this. If you look at the headers of cross platform/multiple compiler supporting libraries you'll always find a lot of defines that use compiler specific constructs to determine such things:
/*Define Microsoft Visual C++ .NET (32-bit) compiler */
#if (defined(_M_IX86) && defined(_MSC_VER) && (_MSC_VER >= 1300)
...
#endif
/*Define Borland 5.0 C++ (16-bit) compiler */
#if defined(__BORLANDC__) && !defined(__WIN32__)
...
#endif
You probably will have to do such defines yourself for all compilers you use.
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
Depending on what you want to achieve, Boost.Config might help you. It does not provide detection of the standard-version, but it provides macros that let you check for support of specific language/compiler-features.
__cplusplus
In C++0x the macro __cplusplus will be set to a value that differs from (is greater than) the current 199711L.
C++0x FAQ by BS
Use __cplusplus as suggested.
Only one note for Microsoft compiler, use Zc:__cplusplus compiler switch to enable __cplusplus
Source https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/
After a quick google:
__STDC__ and __STDC_VERSION__, see here
For cmake projects can use:
if(MSVC)
target_compile_options(mytarget PUBLIC "/Zc:__cplusplus")
endif()
Font: https://peter-bloomfield-online.translate.goog/report-__cplusplus-correctly-with-cmake-and-visual-studio/?_x_tr_sl=en&_x_tr_tl=pt&_x_tr_hl=pt-BR&_x_tr_pto=sc

What is #defined if a compiler is Cpp0x compliant?

Is there any official, or inofficial, #defines for when a compiler is Cpp0x compliant?
Even better, for specific Cpp0x functionality (~#cpp0xlambda, #cpp0xrvalue etc)?
(Haven't found anything about this on the net)
For C++03 according to 16.8/1 (Predefined macro names):
The name __cplusplus is defined to the value 199711L when compiling a C++ translation unit.
For C++0x draft n2857 according to 16.8/1 (Predefined macro names):
The name __cplusplus is defined to the value [tbd] when compiling a C++ translation unit.
Bjarne's C++0x FAQ says:
__cplusplus
In C++0x the macro __cplusplus will be set to a value that differs from (is greater than) the current 199711L.
The official spec includes a value for the __cplusplus preprocessor macro, but as others have pointed out, this suggests that everything in the spec is implemented. More to the point, no current compiler (that I know of) sets the appropriate value. Specs are well and good, but completely unimplemented bits of any spec should be considered tentative; the intersection of the spec and wide support is the real "standard".
A related question is "how can I tell if at least some C++0x support is enabled?", e.g. with the -std=c++0x compiler switch. The answer to that question is compiler-specific and subject to change, but both GCC 4.6 and Clang 2.1 set the preprocessor macro __GXX_EXPERIMENTAL_CXX0X__ (and give it value 1) when their partial C++0x support is enabled.