142 lines
4.6 KiB
C
142 lines
4.6 KiB
C
|
// Implementation of C++14's make_unique for C++11 compilers.
|
||
|
//
|
||
|
// This has been tested with:
|
||
|
// - MSVC 11.0 (Visual Studio 2012)
|
||
|
// - gcc 4.6.3
|
||
|
// - Xcode 4.4 (with clang "4.0")
|
||
|
//
|
||
|
// It is based off an implementation proposed by Stephan T. Lavavej for
|
||
|
// inclusion in the C++14 standard:
|
||
|
// http://isocpp.org/files/papers/N3656.txt
|
||
|
// Where appropriate, it borrows the use of MSVC's _VARIADIC_EXPAND_0X macro
|
||
|
// machinery to compensate for lack of variadic templates.
|
||
|
//
|
||
|
// This file injects make_unique into the std namespace, which I acknowledge is
|
||
|
// technically forbidden ([C++11: 17.6.4.2.2.1/1]), but is necessary in order
|
||
|
// to have syntax compatibility with C++14.
|
||
|
//
|
||
|
// I perform compiler version checking for MSVC, gcc, and clang to ensure that
|
||
|
// we don't add make_unique if it is already there (instead, we include
|
||
|
// <memory> to get the compiler-provided one). You can override the compiler
|
||
|
// version checking by defining the symbol COMPILER_SUPPORTS_MAKE_UNIQUE.
|
||
|
//
|
||
|
//
|
||
|
// ===============================================================================
|
||
|
// This file is released into the public domain. See LICENCE for more information.
|
||
|
// ===============================================================================
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
// If user hasn't specified COMPILER_SUPPORTS_MAKE_UNIQUE then try to figure out
|
||
|
// based on compiler version if std::make_unique is provided.
|
||
|
#if !defined(COMPILER_SUPPORTS_MAKE_UNIQUE)
|
||
|
#if defined(_MSC_VER)
|
||
|
// std::make_unique was added in MSVC 12.0
|
||
|
#if _MSC_VER >= 1800 // MSVC 12.0 (Visual Studio 2013)
|
||
|
#define COMPILER_SUPPORTS_MAKE_UNIQUE
|
||
|
#endif
|
||
|
#elif defined(__clang__)
|
||
|
// std::make_unique was added in clang 3.4, but not until Xcode 6.
|
||
|
// Annoyingly, Apple makes the clang version defines match the version
|
||
|
// of Xcode, not the version of clang.
|
||
|
#define CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
|
||
|
#if defined(__APPLE__) && CLANG_VERSION >= 60000
|
||
|
#define COMPILER_SUPPORTS_MAKE_UNIQUE
|
||
|
#elif !defined(__APPLE__) && CLANG_VERSION >= 30400
|
||
|
#define COMPILER_SUPPORTS_MAKE_UNIQUE
|
||
|
#endif
|
||
|
#elif defined(__GNUC__)
|
||
|
// std::make_unique was added in gcc 4.9, for standards versions greater
|
||
|
// than -std=c++11.
|
||
|
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
|
||
|
#if GCC_VERSION >= 40900 && __cplusplus > 201103L
|
||
|
#define COMPILER_SUPPORTS_MAKE_UNIQUE
|
||
|
#endif
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#if defined(COMPILER_SUPPORTS_MAKE_UNIQUE)
|
||
|
|
||
|
// If the compiler supports std::make_unique, then pull in <memory> to get it.
|
||
|
#include <memory>
|
||
|
|
||
|
#else
|
||
|
|
||
|
// Otherwise, the compiler doesn't provide it, so implement it ourselves.
|
||
|
|
||
|
#include <cstddef>
|
||
|
#include <memory>
|
||
|
#include <type_traits>
|
||
|
#include <utility>
|
||
|
|
||
|
namespace std {
|
||
|
|
||
|
template<class _Ty> struct _Unique_if {
|
||
|
typedef unique_ptr<_Ty> _Single_object;
|
||
|
};
|
||
|
|
||
|
template<class _Ty> struct _Unique_if<_Ty[]> {
|
||
|
typedef unique_ptr<_Ty[]> _Unknown_bound;
|
||
|
};
|
||
|
|
||
|
template<class _Ty, size_t N> struct _Unique_if<_Ty[N]> {
|
||
|
typedef void _Known_bound;
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// template< class T, class... Args >
|
||
|
// unique_ptr<T> make_unique( Args&&... args);
|
||
|
//
|
||
|
|
||
|
#if defined(_MSC_VER) && (_MSC_VER < 1800)
|
||
|
|
||
|
// Macro machinery because MSVC 11.0 doesn't support variadic templates.
|
||
|
// The _VARIADIC_EXPAND_0X stuff is defined in <xstddef>
|
||
|
#define _MAKE_UNIQUE( \
|
||
|
TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, X1, X2, X3, X4) \
|
||
|
template<class _Ty COMMA LIST(_CLASS_TYPE)> inline \
|
||
|
typename _Unique_if<_Ty>::_Single_object make_unique(LIST(_TYPE_REFREF_ARG)) \
|
||
|
{ \
|
||
|
return unique_ptr<_Ty>(new _Ty(LIST(_FORWARD_ARG))); \
|
||
|
} \
|
||
|
|
||
|
_VARIADIC_EXPAND_0X(_MAKE_UNIQUE, , , , )
|
||
|
#undef _MAKE_UNIQUE
|
||
|
|
||
|
#else // not MSVC 11.0 or earlier
|
||
|
|
||
|
template<class _Ty, class... Args>
|
||
|
typename _Unique_if<_Ty>::_Single_object
|
||
|
make_unique(Args&&... args) {
|
||
|
return unique_ptr<_Ty>(new _Ty(std::forward<Args>(args)...));
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
// template< class T >
|
||
|
// unique_ptr<T> make_unique( std::size_t size );
|
||
|
|
||
|
template<class _Ty>
|
||
|
typename _Unique_if<_Ty>::_Unknown_bound
|
||
|
make_unique(size_t n) {
|
||
|
typedef typename remove_extent<_Ty>::type U;
|
||
|
return unique_ptr<_Ty>(new U[n]());
|
||
|
}
|
||
|
|
||
|
// template< class T, class... Args >
|
||
|
// /* unspecified */ make_unique( Args&&... args ) = delete;
|
||
|
|
||
|
// MSVC 11.0 doesn't support deleted functions, so the best we can do
|
||
|
// is simply not define the function.
|
||
|
#if !(defined(_MSC_VER) && (_MSC_VER < 1800))
|
||
|
|
||
|
template<class T, class... Args>
|
||
|
typename _Unique_if<T>::_Known_bound
|
||
|
make_unique(Args&&...) = delete;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
} // namespace std
|
||
|
|
||
|
#endif // !COMPILER_SUPPORTS_MAKE_UNIQUE
|