mirror of
https://github.com/boostorg/core.git
synced 2025-07-29 12:27:42 +02:00
Implement constexpr addressof
This commit is contained in:
@ -1,162 +1,250 @@
|
||||
// Copyright (C) 2002 Brad King (brad.king@kitware.com)
|
||||
// Douglas Gregor (gregod@cs.rpi.edu)
|
||||
//
|
||||
// Copyright (C) 2002, 2008, 2013 Peter Dimov
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
/*
|
||||
Copyright (C) 2002 Brad King (brad.king@kitware.com)
|
||||
Douglas Gregor (gregod@cs.rpi.edu)
|
||||
|
||||
// For more information, see http://www.boost.org
|
||||
Copyright (C) 2002, 2008, 2013 Peter Dimov
|
||||
|
||||
Copyright (C) 2017 Glen Joseph Fernandes (glenjofe@gmail.com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See
|
||||
accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#ifndef BOOST_CORE_ADDRESSOF_HPP
|
||||
#define BOOST_CORE_ADDRESSOF_HPP
|
||||
|
||||
# include <boost/config.hpp>
|
||||
# include <boost/detail/workaround.hpp>
|
||||
# include <cstddef>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <cstddef>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
#if defined(BOOST_NO_SFINAE_EXPR) || \
|
||||
defined(BOOST_NO_CXX11_RVALUE_REFERENCES) || \
|
||||
defined(BOOST_NO_CXX11_CONSTEXPR) || \
|
||||
defined(BOOST_NO_CXX11_DECLTYPE) || \
|
||||
(defined(BOOST_MSVC) && \
|
||||
BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1900)))
|
||||
#define BOOST_CORE_NO_CONSTEXPR_ADDRESSOF
|
||||
#endif
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class T> struct addr_impl_ref
|
||||
{
|
||||
T & v_;
|
||||
|
||||
BOOST_FORCEINLINE addr_impl_ref( T & v ): v_( v ) {}
|
||||
BOOST_FORCEINLINE operator T& () const { return v_; }
|
||||
namespace boost {
|
||||
namespace core {
|
||||
namespace detail {
|
||||
|
||||
template<class T>
|
||||
class addressof_ref {
|
||||
public:
|
||||
BOOST_FORCEINLINE addressof_ref(T& o) BOOST_NOEXCEPT
|
||||
: o_(o) { }
|
||||
BOOST_FORCEINLINE operator T&() const BOOST_NOEXCEPT {
|
||||
return o_;
|
||||
}
|
||||
private:
|
||||
addr_impl_ref & operator=(const addr_impl_ref &);
|
||||
T& o_;
|
||||
};
|
||||
|
||||
template<class T> struct addressof_impl
|
||||
{
|
||||
static BOOST_FORCEINLINE T * f( T & v, long )
|
||||
{
|
||||
return reinterpret_cast<T*>(
|
||||
&const_cast<char&>(reinterpret_cast<const volatile char &>(v)));
|
||||
template<class T>
|
||||
struct address_of {
|
||||
static BOOST_FORCEINLINE T* get(T& o, long) BOOST_NOEXCEPT {
|
||||
return reinterpret_cast<T*>(&
|
||||
const_cast<char&>(reinterpret_cast<const volatile char&>(o)));
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE T * f( T * v, int )
|
||||
{
|
||||
return v;
|
||||
static BOOST_FORCEINLINE T* get(T* p, int) BOOST_NOEXCEPT {
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined( BOOST_NO_CXX11_NULLPTR )
|
||||
|
||||
#if !defined( BOOST_NO_CXX11_DECLTYPE ) && ( ( defined( __clang__ ) && !defined( _LIBCPP_VERSION ) ) || defined( __INTEL_COMPILER ) )
|
||||
|
||||
typedef decltype(nullptr) addr_nullptr_t;
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_NULLPTR)
|
||||
#if !defined(BOOST_NO_CXX11_DECLTYPE) && \
|
||||
(defined(__INTEL_COMPILER) || \
|
||||
(defined(__clang__) && !defined(_LIBCPP_VERSION)))
|
||||
typedef decltype(nullptr) null_type;
|
||||
#else
|
||||
|
||||
typedef std::nullptr_t addr_nullptr_t;
|
||||
|
||||
typedef std::nullptr_t null_type;
|
||||
#endif
|
||||
|
||||
template<> struct addressof_impl< addr_nullptr_t >
|
||||
{
|
||||
typedef addr_nullptr_t T;
|
||||
|
||||
static BOOST_FORCEINLINE T * f( T & v, int )
|
||||
{
|
||||
return &v;
|
||||
template<>
|
||||
struct address_of<null_type> {
|
||||
typedef null_type type;
|
||||
static BOOST_FORCEINLINE type* get(type& o, int) BOOST_NOEXCEPT {
|
||||
return &o;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct addressof_impl< addr_nullptr_t const >
|
||||
{
|
||||
typedef addr_nullptr_t const T;
|
||||
|
||||
static BOOST_FORCEINLINE T * f( T & v, int )
|
||||
{
|
||||
return &v;
|
||||
template<>
|
||||
struct address_of<const null_type> {
|
||||
typedef const null_type type;
|
||||
static BOOST_FORCEINLINE type* get(type& o, int) BOOST_NOEXCEPT {
|
||||
return &o;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct addressof_impl< addr_nullptr_t volatile >
|
||||
{
|
||||
typedef addr_nullptr_t volatile T;
|
||||
|
||||
static BOOST_FORCEINLINE T * f( T & v, int )
|
||||
{
|
||||
return &v;
|
||||
template<>
|
||||
struct address_of<volatile null_type> {
|
||||
typedef volatile null_type type;
|
||||
static BOOST_FORCEINLINE type* get(type& o, int) BOOST_NOEXCEPT {
|
||||
return &o;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct addressof_impl< addr_nullptr_t const volatile >
|
||||
{
|
||||
typedef addr_nullptr_t const volatile T;
|
||||
|
||||
static BOOST_FORCEINLINE T * f( T & v, int )
|
||||
{
|
||||
return &v;
|
||||
template<>
|
||||
struct address_of<const volatile null_type> {
|
||||
typedef const volatile null_type type;
|
||||
static BOOST_FORCEINLINE type* get(type& o, int) BOOST_NOEXCEPT {
|
||||
return &o;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
#if defined(BOOST_CORE_NO_CONSTEXPR_ADDRESSOF)
|
||||
template<class T>
|
||||
BOOST_FORCEINLINE T*
|
||||
addressof(T& o) BOOST_NOEXCEPT
|
||||
{
|
||||
#if (defined(__BORLANDC__) && \
|
||||
BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x610))) || \
|
||||
(defined(__SUNPRO_CC) && \
|
||||
BOOST_WORKAROUND(__SUNPRO_CC, <= 0x5120))
|
||||
return address_of<T>::get(o, 0);
|
||||
#else
|
||||
return address_of<T>::get(addressof_ref<T>(o), 0);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
template<class T>
|
||||
struct add_rvalue_reference {
|
||||
typedef T&& type;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
typename add_rvalue_reference<T>::type declval() BOOST_NOEXCEPT;
|
||||
|
||||
template<class>
|
||||
struct make_void {
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
template<class T, class E = void>
|
||||
struct has_member_address_operator {
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct has_member_address_operator<T,
|
||||
typename make_void<decltype(declval<T&>().operator&())>::type> {
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
#if defined(BOOST_INTEL) && BOOST_WORKAROUND(BOOST_INTEL, < 1600)
|
||||
struct addressable { };
|
||||
|
||||
addressable* operator&(addressable&) BOOST_NOEXCEPT;
|
||||
#endif
|
||||
|
||||
template<class T, class E = void>
|
||||
struct has_non_member_address_operator {
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct has_non_member_address_operator<T,
|
||||
typename make_void<decltype(operator&(declval<T&>()))>::type> {
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
template<class T, class E = void>
|
||||
struct is_addressable {
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct is_addressable<T,
|
||||
typename make_void<decltype(&declval<T&>())>::type> {
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct has_constexpr_address {
|
||||
static constexpr bool value = is_addressable<T>::value &&
|
||||
!has_member_address_operator<T>::value &&
|
||||
!has_non_member_address_operator<T>::value;
|
||||
};
|
||||
|
||||
template<bool E, class T>
|
||||
struct address_if { };
|
||||
|
||||
template<class T>
|
||||
struct address_if<true, T> {
|
||||
typedef T* type;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
BOOST_FORCEINLINE
|
||||
T * addressof( T & v )
|
||||
typename address_if<!has_constexpr_address<T>::value, T>::type
|
||||
addressof(T& o) BOOST_NOEXCEPT
|
||||
{
|
||||
#if (defined( __BORLANDC__ ) && BOOST_WORKAROUND( __BORLANDC__, BOOST_TESTED_AT( 0x610 ) ) ) || (defined(__SUNPRO_CC) && BOOST_WORKAROUND(__SUNPRO_CC, <= 0x5120))
|
||||
|
||||
return boost::detail::addressof_impl<T>::f( v, 0 );
|
||||
|
||||
#else
|
||||
|
||||
return boost::detail::addressof_impl<T>::f( boost::detail::addr_impl_ref<T>( v ), 0 );
|
||||
|
||||
#endif
|
||||
return address_of<T>::get(addressof_ref<T>(o), 0);
|
||||
}
|
||||
|
||||
#if defined( __SUNPRO_CC ) && BOOST_WORKAROUND( __SUNPRO_CC, BOOST_TESTED_AT( 0x590 ) )
|
||||
|
||||
namespace detail
|
||||
template<class T>
|
||||
constexpr BOOST_FORCEINLINE
|
||||
typename address_if<has_constexpr_address<T>::value, T>::type
|
||||
addressof(T& o) BOOST_NOEXCEPT
|
||||
{
|
||||
return &o;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<class T> struct addressof_addp
|
||||
} /* detail */
|
||||
} /* core */
|
||||
|
||||
template<class T>
|
||||
BOOST_CONSTEXPR BOOST_FORCEINLINE T*
|
||||
addressof(T& o) BOOST_NOEXCEPT
|
||||
{
|
||||
typedef T * type;
|
||||
return core::detail::addressof(o);
|
||||
}
|
||||
|
||||
#if defined(BOOST_CORE_NO_CONSTEXPR_ADDRESSOF)
|
||||
#if defined(__SUNPRO_CC) && \
|
||||
BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
|
||||
namespace core {
|
||||
namespace detail {
|
||||
|
||||
template<class T>
|
||||
struct add_pointer {
|
||||
typedef T* type;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} /* detail */
|
||||
} /* core */
|
||||
|
||||
template< class T, std::size_t N >
|
||||
BOOST_FORCEINLINE
|
||||
typename detail::addressof_addp< T[N] >::type addressof( T (&t)[N] )
|
||||
template<class T, std::size_t N>
|
||||
BOOST_FORCEINLINE typename core::detail::add_pointer<T[N]>::type
|
||||
addressof(T (&o)[N]) BOOST_NOEXCEPT
|
||||
{
|
||||
return &t;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Borland doesn't like casting an array reference to a char reference
|
||||
// but these overloads work around the problem.
|
||||
#if defined( __BORLANDC__ ) && BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
|
||||
template<typename T,std::size_t N>
|
||||
BOOST_FORCEINLINE
|
||||
T (*addressof(T (&t)[N]))[N]
|
||||
{
|
||||
return reinterpret_cast<T(*)[N]>(&t);
|
||||
}
|
||||
|
||||
template<typename T,std::size_t N>
|
||||
BOOST_FORCEINLINE
|
||||
const T (*addressof(const T (&t)[N]))[N]
|
||||
{
|
||||
return reinterpret_cast<const T(*)[N]>(&t);
|
||||
return &o;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace boost
|
||||
#if defined(__BORLANDC__) && \
|
||||
BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
|
||||
template<class T, std::size_t N>
|
||||
BOOST_FORCEINLINE
|
||||
T (*addressof(T (&o)[N]) BOOST_NOEXCEPT)[N]
|
||||
{
|
||||
return reinterpret_cast<T(*)[N]>(&o);
|
||||
}
|
||||
|
||||
#endif // BOOST_CORE_ADDRESSOF_HPP
|
||||
template<class T, std::size_t N>
|
||||
BOOST_FORCEINLINE
|
||||
const T (*addressof(const T (&o)[N]) BOOST_NOEXCEPT)[N]
|
||||
{
|
||||
return reinterpret_cast<const T(*)[N]>(&o);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
} /* boost */
|
||||
|
||||
#endif
|
||||
|
@ -13,6 +13,7 @@ run addressof_test.cpp ;
|
||||
run addressof_test2.cpp ;
|
||||
run addressof_np_test.cpp ;
|
||||
run addressof_fn_test.cpp ;
|
||||
compile addressof_constexpr_test.cpp ;
|
||||
|
||||
run checked_delete_test.cpp ;
|
||||
compile-fail checked_delete_fail.cpp ;
|
||||
|
21
test/addressof_constexpr_test.cpp
Normal file
21
test/addressof_constexpr_test.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
Copyright 2017 Glen Joseph Fernandes
|
||||
<glenjofe -at- gmail.com>
|
||||
|
||||
Distributed under the Boost Software
|
||||
License, Version 1.0.
|
||||
http://boost.org/LICENSE_1_0.txt
|
||||
*/
|
||||
|
||||
#include <boost/core/addressof.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
#if !defined(BOOST_CORE_NO_CONSTEXPR_ADDRESSOF)
|
||||
struct Type { };
|
||||
|
||||
static int v1 = 0;
|
||||
static Type v2 = { };
|
||||
|
||||
BOOST_STATIC_ASSERT(boost::addressof(v1) == &v1);
|
||||
BOOST_STATIC_ASSERT(boost::addressof(v2) == &v2);
|
||||
#endif
|
Reference in New Issue
Block a user