53

If have some code where I would like to use C++11x extensions as much as possible, but have a fallback if this is not supported. Currently the OSX version of GCC and the VisualC compiler has little to no support for C++11x, so I use:

#if (defined(__APPLE__) || (defined(_WIN32)))
   ...fallback code without C++11x ...
#else
   ... code using C++11x ...
#endif

And this works, but is not really the right thing to do, especially since the gcc compiler in MacPorts DOES support c++11x.

Is there a #define C11X_SUPPORTED type macro? Perhaps something only GCC has?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Kenneth
  • 718
  • 1
  • 5
  • 7
  • 3
    The problem is that GCC does not fully support C++11 yet, so it really depends on what features you want to use. – juanchopanza May 23 '12 at 09:56
  • 4
    will boost work: http://www.boost.org/doc/libs/1_49_0/libs/config/doc/html/boost_config/boost_macro_reference.html#boost_config.boost_macro_reference.macros_that_describe_c__11_features_not_supported ? – rve May 23 '12 at 10:31
  • 1
    @rve: Why didn't you post it as an answer? It is a good one. – Juraj Blaho May 23 '12 at 10:44

3 Answers3

55

__cplusplus should be defined as 199711L in pre-C++11 compilers, 201103L in those suporting C++11. Whether this is much help in practice is another question: most compilers are only halfway there, so shouldn't be defining it as 201103L, even if they support the features you are interested in. And it's not unheard of for a compiler to lie: a compiler which defines it as 199711L and doesn't support export for templates, for example. But there's no standard feature by feature test.

The simplest solution is just not to use any particular new feature until you can be sure that all compilers support it. You have to write and support the fallback code anyway; why maintain two versions. The one exception to this rule might be new features which impact on performance: whether the compiler supports move semantics or not. In such cases, I'd suggest a compiler dependent include file, which you write yourself based on the compiler documentation and personal tests; just because the compiler may document that it supports a specific feature doesn't mean that its support is bug-free. Just create a directory per targeted compiler, put this file there and specify the appropriate -I or /I option in your makefile or project file.

And your tests should be something along the lines of:

#ifdef HAS_MOVE_SEMANTICS
...
#endif

rather than just on the compiler, version or whatever.

Tom Tanner
  • 9,244
  • 3
  • 33
  • 61
James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • "And it's not unheard of for a compiler to lie" - and GCC surprisingly tells the truth. Or rather, some versions do. Prior to about 4.7-ish, `__cplusplus` is `1`, which is correct since it's not a complete implementation of C++98. Then it was changed to claim conformance in C++98 mode. – Steve Jessop May 23 '12 at 10:19
  • @SteveJessop g++ has never had a complete implementation of C++98 or C++03. It never implemented `export`. So if `__cplusplus` was `199711L`, it was lying. (Of course, it's far from being alone in this situation.) – James Kanze May 23 '12 at 10:21
  • 7
    That's what I'm saying, GCC has recently been changed to lie, whereas previously it told the truth. The reason is that it was impossible to tell whether it was telling the truth about not implementing C++98, or telling the truth about not implementing C++11. Now you can distinguish between when it lies about implementing C++98, and when it tells the truth about not implementing C++11. Yippee. I don't think anyone has ever implemented C++98 (or C++03), so the exact value of `__cplusplus` is basically useless. It's always either implementation-specific or lying. – Steve Jessop May 23 '12 at 10:22
  • @SteveJessop That's basically my point. There's something officially there, but it's useless. – James Kanze May 23 '12 at 11:42
  • Testing for individual C++11 features would create a testing nightmare, because (theoretically) every combination of supported features should tested. "All-or-nothing" approach is more practical, and for that purpose `__cplusplus` is just fine. If compiler/library does not support a feature that the code uses, then there should be an error, and whoever is compiling it should either upgrade the compiler, or set flags to build for earlier standard (assuming code supports that). – hyde Aug 16 '14 at 06:27
  • @hyde If it's all or nothing, then you have to eliminate C++11 completely, since no one yet implements it totally. On the other hand, there are a couple of widely implemented features which are quite useful, at least in some applications, and it would be a shame to not use them if they are available. – James Kanze Aug 18 '14 at 08:29
  • @JamesKanze I didn't mean that developer should be forced to use all C++11 features if compiler says it's C++11... I meant, use whatever working subset of C++11 features only if compilers says it's C++11. And if compiler does not support the selected subset fully, then C++03 (TR1) has to be used. Two versions to to choose from and needed to test: C++11 (with whatever subset of it is used by the code) and C++03 (TR1). – hyde Aug 18 '14 at 10:55
  • @hyde I don't quite follow the issue of testing; you have to test with all of the compilers you target, even if there are no conditionals involved. Also, with regards to syntax issues, if even one of your targeted compilers is missing the feature, you shouldn't use it any where. Because if even one compiler doesn't support it, you have to maintain the code which doesn't use it. On the other hand, getting the performance boost from moveable can be important on compilers which support it. – James Kanze Aug 18 '14 at 13:19
  • 1
    @JamesKanze: I would consider `export` a special case, as in consider it as dropped from the C++03 / C++98 standards too, and then consider the question of conformance. Reason being, it was dropped as a bad idea later, and I think there was only one implementation supporting it, or thereabouts. And I'm not sure how well. – Deduplicator Jan 16 '15 at 19:04
  • @Deduplicator My point was more about the validity of checking. `export` was clearly part (and an important part) of C++98. Most compilers went through a stage, however, where they claimed full conformance, but didn't implement `export`. In other words, you can't do an all or nothing check; you really need a separate feature check, defined uniquely for each compiler. – James Kanze Jan 17 '15 at 11:19
  • How to use the same thing for C++14? – fnc12 Aug 06 '16 at 02:35
31

You can check the value of the __cplusplus macro. For C++11, it's greater than 199711L.

So something like

#if __cplusplus > 199711L

#endif
Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
8

The Boost.Config library provides granular preprocessor macros you can use to conditionally compile based on the presence of a given C++11 feature.

(For a compiler, C++11 support need not be an all or nothing proposition. For example, consider how Microsoft cherry picked which C++11 features to include in Visual Studio 2012 based on what they believed would most benefit their customers.)

Edward Brey
  • 40,302
  • 20
  • 199
  • 253