8

I need to backport nullptr to a cross platform library we have, but I'm having trouble getting a reliable check of nullptr support.

Initially I had this:

#if __cplusplus >= 201103L || (__cplusplus < 200000 && __cplusplus >= 199711L)
    // nullptr should be ok
#else
    // Too old
#endif

But then I discovered that compiling a program that just printed out the value of __cplusplus produced unexpected results.

One blog post claimed 199711L was a value that MS compilers use to indicate partial support for C++11. But I notice g++ 5.4 produces that value by default. Until you expressly tell it to use compile with -std=c++11. But then if you tell it the standard is c++98 the value 199711 is still shown. That doesn't sound right to me. So that's not a good check!

Then I saw someone doing this with an answer that claimed it may work. Well it doesn't.

#if !defined(nullptr)
#endif

But I'm not sure you can do that. So I tested it like this:

#if defined(nullptr)
#error "null ptr defined"
#endif

Guess what? that doesn't print out the error when nullptr is actually available. So that doesn't at all.

How do I detect nullptr or compiler version under linux/windows and OSX (clang)/ android.

Community
  • 1
  • 1
hookenz
  • 30,814
  • 37
  • 149
  • 251
  • 1
    If it's not available, your code that uses it won't compile. That seems like a pretty straightforward indicator to me. And why do you think you need to (or can) "backport" it? –  Feb 22 '17 at 20:20
  • Look at Boost.Config's `BOOST_NO_CXX11_NULLPTR` macro. Either use Boost.Config or duplicate the equivalent logic they use to determine this. – GManNickG Feb 22 '17 at 20:21
  • @Matt have you tried a typetrait checking for nullptr_t? sth like std::is_same or sth like that. – jonas_toth Feb 22 '17 at 20:41
  • Why do you want to use `nullptr` with old compilers? It's a nice touch, but `NULL` is almost as good. – Martin Bonner supports Monica Feb 22 '17 at 21:08
  • 2
    Typical XY problem. Just use `NULL` until you don't have to support legacy compilers. – rustyx Feb 22 '17 at 21:23
  • Old compiler will map `NULL` to `0`, compiler that supports `nullptr` can map `NULL` to `nullptr`. (Although not all of them do). – M.M Feb 22 '17 at 21:30
  • @RustyX - this all came about due to someone defining null to be NULL in a library we use to save his pinky. And then clashing with other libs. So we decided to switch to nullptr to make things clear. Can o' worms! – hookenz Feb 22 '17 at 21:32
  • 199711L is the correct value for compliance to the 1998 or 2003 specs, and has nothing to do with "partial C++11 support". – aschepler Feb 22 '17 at 21:37
  • @NeilButterworth - not really a backport, it's just that we had an inhouse library developed over many years that used "null"... because the main dev didn't like using his pinky to write NULL. It seems null was clashing with other libs for other dev's so we thought time to fix it, lets switch to nullptr. But this turned out to be a little more difficult than first thought. defining nullptr to 0 is acceptable for us. The fancy class based one produced more problems than it solved. 0 is fine. – hookenz Feb 22 '17 at 22:08
  • 2
    @matt that last edit should be an answer instead. – NathanOliver Feb 22 '17 at 22:09

2 Answers2

8
  • If you're using Boost, Boost.Config provides the BOOST_NO_CXX11_NULLPTR macro.

    Boost implements this by defining it for each compiler-version-combo that doesn't support it, so you cannot easily duplicate the functionality.

  • If you're using CMake, you can use compiler feature detection (specifically cxx_nullptr) to conditionally define a macro.

#if !defined(nullptr) doesn't work because nullptr is not a macro.

emlai
  • 37,861
  • 9
  • 87
  • 140
  • regarding #if !defined(nullptr), that's what I thought too but so many people were posting answers to a question that had implemented the check that way reinforcing it as correct. So I began to doubt what I assumed was true. That's for confirming my first thought. – hookenz Feb 22 '17 at 20:29
  • @Matt have you tried a typetrait checking for nullptr_t? sth like std::is_same or sth like that. – jonas_toth Feb 22 '17 at 20:40
  • Doesn't Boost build this configuration when you install the library? So, unless you have a complete list of supported compilers or some external build tool to test for language features, this solution can't be used when distributing a header only library? – Mikhail Feb 22 '17 at 20:46
  • So we aren't using boost and I can't included boost headers in this thing, so what I ended up doing was pulling out the boost library and extracting the needed parts. – hookenz Feb 22 '17 at 21:53
3

Thanks to the hints to the boost library this is what I ended up with. I'm sure I'm not the only one who wants this.

#if defined(__GNUC__)
#  define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#  if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
#    define GCC_CXX11
#  endif
#  if (GCC_VERSION < 40600) || !defined(GCC_CXX11)
#    define NO_CXX11_NULLPTR
#  endif
#endif

#if defined(_MSC_VER)
#  if (_MSC_VER < 1600)
#    define NO_CXX11_NULLPTR
#  endif
#endif

#if defined(__clang__)
#  if !__has_feature(cxx_nullptr)
#    define NO_CXX11_NULLPTR
#  endif
#endif

#if defined(NO_CXX11_NULLPTR)
#  pragma message("Defining nullptr")
#  define nullptr 0
#endif
Barry
  • 247,587
  • 26
  • 487
  • 819