Extracted C++11 implementation of is_nothrow_swappable to a separate header.

Also modified the implementation to avoid referencing any potential swap
overloads in namespace boost, unless these overloads are found by ADL.

Added tests to verify is_nothrow_swappable works with ADL.
This commit is contained in:
Andrey Semashev
2023-02-18 18:55:54 +03:00
parent 2370288a79
commit 1c31fee575
3 changed files with 111 additions and 29 deletions

View File

@ -0,0 +1,37 @@
#ifndef BOOST_TYPE_TRAITS_DETAIL_IS_SWAPPABLE_CXX_11_HPP_INCLUDED
#define BOOST_TYPE_TRAITS_DETAIL_IS_SWAPPABLE_CXX_11_HPP_INCLUDED
// Copyright 2017 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
#include <boost/config.hpp>
#include <boost/type_traits/declval.hpp>
#include <boost/type_traits/integral_constant.hpp>
#if __cplusplus >= 201103L || defined(BOOST_DINKUMWARE_STDLIB)
#include <utility> // for std::swap (C++11)
#else
#include <algorithm> // for std::swap (C++98)
#endif
// Intentionally not within boost namespace to avoid implicitly pulling in boost::swap overloads other than through ADL
namespace boost_type_traits_swappable_detail
{
using std::swap;
template<class T, class U, bool B = noexcept(swap(boost::declval<T>(), boost::declval<U>()))> boost::integral_constant<bool, B> is_nothrow_swappable_with_impl( int );
template<class T, class U> boost::false_type is_nothrow_swappable_with_impl( ... );
template<class T, class U>
struct is_nothrow_swappable_with_helper { typedef decltype( boost_type_traits_swappable_detail::is_nothrow_swappable_with_impl<T, U>(0) ) type; };
template<class T, bool B = noexcept(swap(boost::declval<T&>(), boost::declval<T&>()))> boost::integral_constant<bool, B> is_nothrow_swappable_impl( int );
template<class T> boost::false_type is_nothrow_swappable_impl( ... );
template<class T>
struct is_nothrow_swappable_helper { typedef decltype( boost_type_traits_swappable_detail::is_nothrow_swappable_impl<T>(0) ) type; };
} // namespace boost_type_traits_swappable_detail
#endif // #ifndef BOOST_TYPE_TRAITS_DETAIL_IS_SWAPPABLE_CXX_11_HPP_INCLUDED

View File

@ -28,35 +28,16 @@ template <class T> struct is_nothrow_swappable_with<T, T> : is_nothrow_swappable
#else
#include <boost/type_traits/declval.hpp>
#include <boost/type_traits/integral_constant.hpp>
#include <algorithm>
#include <boost/type_traits/detail/is_swappable_cxx_11.hpp>
namespace boost
{
namespace type_traits_swappable_detail
{
using std::swap;
template<class T, class U, bool B = noexcept(swap(declval<T>(), declval<U>()))> integral_constant<bool, B> is_nothrow_swappable_with_impl( int );
template<class T, class U> false_type is_nothrow_swappable_with_impl( ... );
template<class T, class U>
struct is_nothrow_swappable_with_helper { typedef decltype( type_traits_swappable_detail::is_nothrow_swappable_with_impl<T, U>(0) ) type; };
template<class T, bool B = noexcept(swap(declval<T&>(), declval<T&>()))> integral_constant<bool, B> is_nothrow_swappable_impl( int );
template<class T> false_type is_nothrow_swappable_impl( ... );
template<class T>
struct is_nothrow_swappable_helper { typedef decltype( type_traits_swappable_detail::is_nothrow_swappable_impl<T>(0) ) type; };
} // namespace type_traits_swappable_detail
template<class T, class U> struct is_nothrow_swappable_with: type_traits_swappable_detail::is_nothrow_swappable_with_helper<T, U>::type
template<class T, class U> struct is_nothrow_swappable_with: boost_type_traits_swappable_detail::is_nothrow_swappable_with_helper<T, U>::type
{
};
template<class T> struct is_nothrow_swappable: type_traits_swappable_detail::is_nothrow_swappable_helper<T>::type
template<class T> struct is_nothrow_swappable: boost_type_traits_swappable_detail::is_nothrow_swappable_helper<T>::type
{
};

View File

@ -1,4 +1,3 @@
// Copyright 2017 Peter Dimov
//
// Distributed under the Boost Software License, Version 1.0.
@ -17,6 +16,13 @@
#include "check_integral_constant.hpp"
#include <utility>
// These conditions should be similar to those in is_nothrow_swappable.hpp
#if defined(BOOST_NO_SFINAE_EXPR) || defined(BOOST_NO_CXX11_NOEXCEPT) || defined(BOOST_NO_CXX11_DECLTYPE) || defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) \
|| BOOST_WORKAROUND(BOOST_GCC, < 40700) \
|| (defined(__GLIBCXX__) && __GLIBCXX__ <= 20120301) // built-in clang++ -std=c++11 on Travis, w/ libstdc++ 4.6
#define BOOST_TYPE_TRAITS_IS_NOTHROW_SWAPPABLE_EMULATED
#endif
struct X
{
};
@ -45,6 +51,44 @@ struct U
void swap(U&, U&) {}
#if !defined(BOOST_TYPE_TRAITS_IS_NOTHROW_SWAPPABLE_EMULATED) && !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS)
namespace test_ns {
// Not swappable using std::swap, but swappable using test_ns::swap
struct only_adl_swappable
{
only_adl_swappable(only_adl_swappable const&) = delete;
only_adl_swappable& operator= (only_adl_swappable const&) = delete;
};
inline void swap(only_adl_swappable&, only_adl_swappable&) BOOST_NOEXCEPT {}
} // namespace test_ns
namespace boost {
namespace type_traits_is_nothrow_swappable_test {
// Some type that is defined within boost namespace and that has a specialized swap overload
struct swappable
{
swappable(swappable const&) = delete;
swappable& operator= (swappable const&) = delete;
};
// This overload should be selected by is_nothrow_swappable
inline void swap(swappable&, swappable&) BOOST_NOEXCEPT {}
} // namespace type_traits_is_nothrow_swappable_test
// Some generic swap implementation, such as the one from Boost.Swap. This overload should *not* be selected by is_nothrow_swappable.
template< typename T1, typename T2 >
inline void swap(T1&, T2&) {}
} // namespace boost
#endif
TT_TEST_BEGIN(is_nothrow_swappable)
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<int>::value, true);
@ -52,9 +96,7 @@ BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<int const>::value, fals
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<int volatile>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<int const volatile>::value, false);
#if defined(BOOST_NO_SFINAE_EXPR) || defined(BOOST_NO_CXX11_NOEXCEPT) || defined(BOOST_NO_CXX11_DECLTYPE) || defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) \
|| BOOST_WORKAROUND(BOOST_GCC, < 40700)\
|| (defined(__GLIBCXX__) && __GLIBCXX__ <= 20120301) // built-in clang++ -std=c++11 on Travis, w/ libstdc++ 4.6
#if defined(BOOST_TYPE_TRAITS_IS_NOTHROW_SWAPPABLE_EMULATED)
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<int[2]>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<int const[2]>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<int volatile[2]>::value, false);
@ -71,9 +113,7 @@ BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<void const>::value, fal
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<void volatile>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<void const volatile>::value, false);
#if defined(BOOST_NO_SFINAE_EXPR) || defined(BOOST_NO_CXX11_NOEXCEPT) || defined(BOOST_NO_CXX11_DECLTYPE) || defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) \
|| BOOST_WORKAROUND(BOOST_GCC, < 40700)\
|| (defined(__GLIBCXX__) && __GLIBCXX__ <= 20120301) // built-in clang++ -std=c++11 on Travis, w/ libstdc++ 4.6
#if defined(BOOST_TYPE_TRAITS_IS_NOTHROW_SWAPPABLE_EMULATED)
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<X>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<X const>::value, false);
@ -157,6 +197,30 @@ BOOST_CHECK_INTEGRAL_CONSTANT((::tt::is_nothrow_swappable<std::pair<V, int> cons
BOOST_CHECK_INTEGRAL_CONSTANT((::tt::is_nothrow_swappable<std::pair<V, int> volatile>::value), false);
BOOST_CHECK_INTEGRAL_CONSTANT((::tt::is_nothrow_swappable<std::pair<V, int> const volatile>::value), false);
#if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS)
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<test_ns::only_adl_swappable>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<test_ns::only_adl_swappable const>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<test_ns::only_adl_swappable volatile>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<test_ns::only_adl_swappable const volatile>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<test_ns::only_adl_swappable[2]>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<test_ns::only_adl_swappable const[2]>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<test_ns::only_adl_swappable volatile[2]>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<test_ns::only_adl_swappable const volatile[2]>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<boost::type_traits_is_nothrow_swappable_test::swappable>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<boost::type_traits_is_nothrow_swappable_test::swappable const>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<boost::type_traits_is_nothrow_swappable_test::swappable volatile>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<boost::type_traits_is_nothrow_swappable_test::swappable const volatile>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<boost::type_traits_is_nothrow_swappable_test::swappable[2]>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<boost::type_traits_is_nothrow_swappable_test::swappable const[2]>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<boost::type_traits_is_nothrow_swappable_test::swappable volatile[2]>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_nothrow_swappable<boost::type_traits_is_nothrow_swappable_test::swappable const volatile[2]>::value, false);
#endif // !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS)
#endif
TT_TEST_END