michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=8 sts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * Implements a workaround for compilers which do not support the C++11 nullptr michael@0: * constant. michael@0: */ michael@0: michael@0: #ifndef mozilla_NullPtr_h michael@0: #define mozilla_NullPtr_h michael@0: michael@0: #if defined(__clang__) michael@0: # if !__has_extension(cxx_nullptr) michael@0: # error "clang version natively supporting nullptr is required." michael@0: # endif michael@0: # define MOZ_HAVE_CXX11_NULLPTR michael@0: #elif defined(__GNUC__) michael@0: # if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L michael@0: # include "mozilla/Compiler.h" michael@0: # if MOZ_GCC_VERSION_AT_LEAST(4, 6, 0) michael@0: # define MOZ_HAVE_CXX11_NULLPTR michael@0: # endif michael@0: # endif michael@0: #elif defined(_MSC_VER) michael@0: // The minimum supported MSVC (10, _MSC_VER 1600) supports nullptr. michael@0: # define MOZ_HAVE_CXX11_NULLPTR michael@0: #endif michael@0: michael@0: namespace mozilla { michael@0: michael@0: /** michael@0: * IsNullPointer::value is true iff T is the type of C++11's nullptr. If michael@0: * nullptr is emulated, IsNullPointer::value is false for all T. michael@0: * michael@0: * IsNullPointer is useful to give an argument the true decltype(nullptr) type. michael@0: * decltype(nullptr) doesn't work when nullptr is emulated. The simplest michael@0: * workaround is to use template overloading and SFINAE to expose an overload michael@0: * only if an argument's type is decltype(nullptr). Some examples (that assume michael@0: * namespace mozilla has been opened, for simplicity): michael@0: * michael@0: * // foo(T*), foo(stuff that converts to T*), and foo(decltype(nullptr)) michael@0: * // (only invoked if nullptr is true nullptr, otherwise foo(T*) is invoked) michael@0: * // but nothing else michael@0: * void foo(T*) { } michael@0: * template michael@0: * void foo(N, michael@0: * typename EnableIf::value, int>::Type dummy = 0) michael@0: * { } michael@0: * michael@0: * // foo(T*) *exactly* and foo(decltype(nullptr)), nothing else michael@0: * void foo(T*) { } michael@0: * template michael@0: * void foo(U, michael@0: * typename EnableIf::value, int>::Type dummy = 0) michael@0: * MOZ_DELETE; michael@0: * michael@0: * The exact details of how set up the SFINAE bits vary on a case-by-case basis. michael@0: * If you need help with this (and unless you've internalized way more sadmaking michael@0: * nullptr-emulation knowledge than you should have, you do), feel free to poke michael@0: * the person with blame on this comment with questions. :-) michael@0: * michael@0: * Ideally this would be in TypeTraits.h, but C++11 omitted std::is_null_pointer michael@0: * (fixed in C++1y), so in the interests of easing a switch to , michael@0: * this trait lives elsewhere. michael@0: */ michael@0: template michael@0: struct IsNullPointer { static const bool value = false; }; michael@0: michael@0: } // namespace mozilla michael@0: michael@0: /** michael@0: * mozilla::NullptrT is a type that's sort of like decltype(nullptr). But it michael@0: * can't be identical, because emulated nullptr doesn't have a distinct type. michael@0: * Only with gcc 4.4/4.5, emulated nullptr is __null, and decltype(__null) is michael@0: * int or long. But passing __null to an int/long parameter triggers michael@0: * -Werror=conversion-null errors with gcc 4.5, or (depending on subsequent use michael@0: * inside the overloaded function) can trigger pointer-to-integer comparison michael@0: * compiler errors. So fairly often, actually, NullptrT is *not* what you want. michael@0: * michael@0: * Instead, often you should use template-based overloading in concert with michael@0: * SFINAE to add a nullptr overload -- see the comments by IsNullPointer. michael@0: * michael@0: * So when *should* you use NullptrT? Thus far, the only truly good use seems michael@0: * to be as an argument type for operator overloads (because C++ doesn't allow michael@0: * operator= to have more than one argument, operator== to have more than two, michael@0: * &c.). But even in such cases, it really only works if there are no other michael@0: * overloads of the operator that accept a pointer type. If you want both T* michael@0: * and nullptr_t overloads, you'll have to wait til we drop gcc 4.4/4.5 support. michael@0: * (Currently b2g is the only impediment to this.) michael@0: */ michael@0: #ifdef MOZ_HAVE_CXX11_NULLPTR michael@0: // decltype does the right thing for actual nullptr. michael@0: namespace mozilla { michael@0: typedef decltype(nullptr) NullptrT; michael@0: template<> michael@0: struct IsNullPointer { static const bool value = true; }; michael@0: } michael@0: # undef MOZ_HAVE_CXX11_NULLPTR michael@0: #elif MOZ_IS_GCC michael@0: # define nullptr __null michael@0: // void* sweeps up more than just nullptr, but compilers supporting true michael@0: // nullptr are the majority now, so they should detect mistakes. If you're michael@0: // feeling paranoid, check/assert that your NullptrT equals nullptr. michael@0: namespace mozilla { typedef void* NullptrT; } michael@0: #else michael@0: # error "No compiler support for nullptr or its emulation." michael@0: #endif michael@0: michael@0: #endif /* mozilla_NullPtr_h */