is_copy_assignable implementation added. It needs C++11 support to work reliable.

This commit is contained in:
Ion Gaztañaga
2014-08-26 23:23:12 +02:00
parent bbcfff0278
commit cf18d2bbac
5 changed files with 423 additions and 0 deletions

View File

@ -0,0 +1,51 @@
[/
Copyright 2007 John Maddock.
Copyright 2014 Ion Gaztanaga.
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).
]
[section:is_copy_assignable is_copy_assignable]
template <class T>
struct is_copy_assignable : public __tof {};
__inherit If `T` is `CopyAssignable` (i.e. has an accessible explicit or implicit copy assignment operator),
then inherits from __true_type, otherwise inherits from __false_type. Type `T`
must be a complete type.
In other words, inherits from __true_type only if copy assignment of `T` from `const T &` is not
marked with `= delete`, `T` does not derives from `boost::noncopyable` and
is not marked with `BOOST_MOVABLE_BUT_NOT_COPYABLE(T)`.
__compat If the compiler does not support partial-specialization of class
templates, then this template can not be used.
If your compiler does not support C++11 deleted functions (`= delete`) or does not support
SFINAE for the deleted assignments, then derive your classes from `boost::noncopyable` or
mark them with `BOOST_MOVABLE_BUT_NOT_COPYABLE(T)` to show that class is non-assignable.
Trait does not care about access modifiers, so if you see errors like this:
'T::operator=(const T&)' is private
boost/type_traits/is_copy_assignable.hpp:68:5: error: within this context
then you are trying to call that macro for a structure with private assignment:
struct T {
// ...
private:
T &operator=(const T &);
// ...
};
To fix that you must modify your structure, explicitly marking it as noncopyable (`= delete`,
`boost::noncopyable` or `BOOST_MOVABLE_BUT_NOT_COPYABLE(T)`) or explicitly
[link boost_typetraits.user_defined specializing the trait].
__header ` #include <boost/type_traits/is_copy_assignable.hpp>` or ` #include <boost/type_traits.hpp>`
[endsect]

View File

@ -69,6 +69,7 @@
[def __is_empty [link boost_typetraits.reference.is_empty is_empty]]
[def __is_const [link boost_typetraits.reference.is_const is_const]]
[def __is_copy_constructible [link boost_typetraits.reference.is_copy_constructible is_copy_constructible]]
[def __is_copy_assignable [link boost_typetraits.reference.is_copy_assignable is_copy_assignable]]
[def __is_volatile [link boost_typetraits.reference.is_volatile is_volatile]]
[def __is_abstract [link boost_typetraits.reference.is_abstract is_abstract]]
[def __is_polymorphic [link boost_typetraits.reference.is_polymorphic is_polymorphic]]

View File

@ -51,6 +51,7 @@
#include "boost/type_traits/is_const.hpp"
#include "boost/type_traits/is_convertible.hpp"
#include "boost/type_traits/is_copy_constructible.hpp"
#include "boost/type_traits/is_copy_assignable.hpp"
#include "boost/type_traits/is_empty.hpp"
#include "boost/type_traits/is_enum.hpp"
#include "boost/type_traits/is_float.hpp"

View File

@ -0,0 +1,147 @@
// (C) Copyright Ion Gaztanaga 2014.
//
// Use, modification and distribution are subject to 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).
//
// See http://www.boost.org/libs/type_traits for most recent version including documentation.
#ifndef BOOST_TT_IS_COPY_ASSIGNABLE_HPP_INCLUDED
#define BOOST_TT_IS_COPY_ASSIGNABLE_HPP_INCLUDED
#include <boost/config.hpp>
#include <boost/type_traits/detail/yes_no_type.hpp>
#include <boost/type_traits/is_base_and_derived.hpp>
#include <boost/noncopyable.hpp>
#if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) && !defined(BOOST_NO_CXX11_DECLTYPE) \
&& !defined(BOOST_INTEL_CXX_VERSION) && \
!(defined(BOOST_MSVC) && _MSC_VER == 1800)
#define BOOST_TT_CXX11_IS_COPY_ASSIGNABLE
#include <boost/utility/declval.hpp>
#else
//For compilers without decltype
#include <boost/type_traits/is_const.hpp>
#include <boost/type_traits/is_array.hpp>
#include <boost/type_traits/add_reference.hpp>
#include <boost/type_traits/remove_reference.hpp>
#endif
// should be the last #include
#include <boost/type_traits/detail/bool_trait_def.hpp>
namespace boost {
namespace detail{
template <bool DerivedFromNoncopyable, class T>
struct is_copy_assignable_impl2 {
// Intel compiler has problems with SFINAE for copy constructors and deleted functions:
//
// error: function *function_name* cannot be referenced -- it is a deleted function
// static boost::type_traits::yes_type test(T1&, decltype(T1(boost::declval<T1&>()))* = 0);
// ^
//
// MSVC 12.0 (Visual 2013) has problems when the copy constructor has been deleted. See:
// https://connect.microsoft.com/VisualStudio/feedback/details/800328/std-is-copy-constructible-is-broken
#if defined(BOOST_TT_CXX11_IS_COPY_ASSIGNABLE)
typedef boost::type_traits::yes_type yes_type;
typedef boost::type_traits::no_type no_type;
template <class U>
static decltype(::boost::declval<U&>() = ::boost::declval<const U&>(), yes_type() ) test(int);
template <class>
static no_type test(...);
static const bool value = sizeof(test<T>(0)) == sizeof(yes_type);
#else
static BOOST_DEDUCED_TYPENAME boost::add_reference<T>::type produce();
template <class T1>
static boost::type_traits::no_type test(T1&, typename T1::boost_move_no_copy_constructor_or_assign* = 0);
static boost::type_traits::yes_type test(...);
// If you see errors like this:
//
// `'T::operator=(const T&)' is private`
// `boost/type_traits/is_copy_assignable.hpp:NN:M: error: within this context`
//
// then you are trying to call that macro for a structure defined like that:
//
// struct T {
// ...
// private:
// T & operator=(const T &);
// ...
// };
//
// To fix that you must modify your structure:
//
// // C++03 and C++11 version
// struct T: private boost::noncopyable {
// ...
// private:
// T & operator=(const T &);
// ...
// };
//
// // C++11 version
// struct T {
// ...
// private:
// T& operator=(const T &) = delete;
// ...
// };
BOOST_STATIC_CONSTANT(bool, value = (
sizeof(test(produce())) == sizeof(boost::type_traits::yes_type)
));
#endif
};
template <class T>
struct is_copy_assignable_impl2<true, T> {
BOOST_STATIC_CONSTANT(bool, value = false);
};
template <class T>
struct is_copy_assignable_impl {
#if !defined(BOOST_TT_CXX11_IS_COPY_ASSIGNABLE)
//For compilers without decltype, at least return false on const types, arrays
//types derived from boost::noncopyable and types defined as BOOST_MOVEABLE_BUT_NOT_COPYABLE
typedef BOOST_DEDUCED_TYPENAME boost::remove_reference<T>::type unreferenced_t;
BOOST_STATIC_CONSTANT(bool, value = (
boost::detail::is_copy_assignable_impl2<
boost::is_base_and_derived<boost::noncopyable, T>::value
|| boost::is_const<unreferenced_t>::value || boost::is_array<unreferenced_t>::value
,T
>::value
));
#else
BOOST_STATIC_CONSTANT(bool, value = (
boost::detail::is_copy_assignable_impl2<
boost::is_base_and_derived<boost::noncopyable, T>::value,T
>::value
));
#endif
};
} // namespace detail
BOOST_TT_AUX_BOOL_TRAIT_DEF1(is_copy_assignable,T,::boost::detail::is_copy_assignable_impl<T>::value)
BOOST_TT_AUX_BOOL_TRAIT_SPEC1(is_copy_assignable,void,false)
#ifndef BOOST_NO_CV_VOID_SPECIALIZATIONS
BOOST_TT_AUX_BOOL_TRAIT_SPEC1(is_copy_assignable,void const,false)
BOOST_TT_AUX_BOOL_TRAIT_SPEC1(is_copy_assignable,void const volatile,false)
BOOST_TT_AUX_BOOL_TRAIT_SPEC1(is_copy_assignable,void volatile,false)
#endif
} // namespace boost
#include <boost/type_traits/detail/bool_trait_undef.hpp>
#endif // BOOST_TT_IS_COPY_ASSIGNABLE_HPP_INCLUDED

223
test/is_copy_assignable.cpp Normal file
View File

@ -0,0 +1,223 @@
// (C) Copyright John Maddock 2000.
// (C) Copyright Ion Gaztanaga 2014.
// Use, modification and distribution are subject to 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)
//#define TEST_STD
#include "test.hpp"
#include "check_integral_constant.hpp"
#ifdef TEST_STD
# include <type_traits>
#else
# include <boost/type_traits/is_copy_assignable.hpp>
#endif
#include <boost/move/core.hpp>
struct has {
has(){}
has &operator=(const has&){ return *this; }
};
// MSVC can not generate neither default constructor, nor assignment operator,
// nor copy constructor for `has2` type. Supressing those warnings is essential,
// because we treat warnings as errors in those tests
#if (defined _MSC_VER)
# pragma warning( push )
# pragma warning( disable : 4510 4512 4610)
#endif
struct has2 {
int i;
has2 &operator=(const int& val) { i = val; return *this; }
};
#if (defined _MSC_VER)
# pragma warning( pop )
#endif
struct has3 { // Copy assignment must be generated by compiler
has3(has3*){}
};
struct has_not: public boost::noncopyable {
typedef boost::noncopyable base_t;
has_not() : base_t() {}
};
#if defined(BOOST_TT_CXX11_IS_COPY_ASSIGNABLE)
struct has_not2 {
has_not2() {}
has_not2& operator=(has_not2&) = delete;
};
struct has_not3 {
has_not3() {}
has_not3& operator=(const has_not3&) = delete;
};
#endif // BOOST_TT_CXX11_IS_COPY_ASSIGNABLE
struct has_not4: private boost::noncopyable {
typedef boost::noncopyable base_t;
has_not4() : base_t() {}
private:
has_not4& operator=(const has_not4&);
};
struct has_not5 {
private:
BOOST_MOVABLE_BUT_NOT_COPYABLE(has_not5)
};
struct has_not6 {
has_not6& operator=(has_not6&){ return *this; }
};
TT_TEST_BEGIN(is_copy_assignable)
// Main part of the test
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<has>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<has2>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<has3>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<has_not>::value, false);
#if defined(BOOST_TT_CXX11_IS_COPY_ASSIGNABLE)
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<has_not2>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<has_not3>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<has_not6>::value, false);
#endif
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<has_not4>::value, false);
// Requires some basic support from Boost.Move in C++03
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<has_not5>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<bool>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<bool const>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<bool volatile>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<bool const volatile>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<signed char>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<signed char const>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<signed char volatile>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<signed char const volatile>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<unsigned char>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<unsigned char const>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<char>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<char const>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<unsigned char volatile>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<unsigned char const volatile>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<char volatile>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<char const volatile>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<unsigned short>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<unsigned short const>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<short>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<short const>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<unsigned short volatile>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<unsigned short const volatile>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<short volatile>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<short const volatile>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<unsigned int>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<unsigned int const>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<int>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<int const>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<unsigned int volatile>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<unsigned int const volatile>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<int volatile>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<int const volatile>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<unsigned long>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<unsigned long const>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<long>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<long const>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<unsigned long volatile>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<unsigned long const volatile>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<long volatile>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<long const volatile>::value, false);
#ifdef BOOST_HAS_LONG_LONG
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable< ::boost::ulong_long_type>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable< ::boost::ulong_long_type const>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable< ::boost::long_long_type>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable< ::boost::long_long_type const>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable< ::boost::ulong_long_type volatile>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable< ::boost::ulong_long_type const volatile>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable< ::boost::long_long_type volatile>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable< ::boost::long_long_type const volatile>::value, false);
#endif
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<float>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<float const>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<float volatile>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<float const volatile>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<double>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<double const>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<double volatile>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<double const volatile>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<long double>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<long double const>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<long double volatile>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<long double const volatile>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<int>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<void*>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<int*const>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<f1>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<f2>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<f3>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<mf1>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<mf2>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<mf3>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<mp>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<cmf>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<enum_UDT>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<int&>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<const int&>::value, false);
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<int&&>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<const int&&>::value, false);
#endif
// Following three tests may give different results because of compiler and C++03/C++11.
// On C++11 compiler following code:
// int c[2][4][5][6][3];
// int b[2][4][5][6][3] = std::move(c);
// does not compile, so we expect `false` to be the result of those three tests.
BOOST_CHECK_SOFT_INTEGRAL_CONSTANT(::tt::is_copy_assignable<int[2]>::value, false, true);
BOOST_CHECK_SOFT_INTEGRAL_CONSTANT(::tt::is_copy_assignable<int[3][2]>::value, false, true);
BOOST_CHECK_SOFT_INTEGRAL_CONSTANT(::tt::is_copy_assignable<int[2][4][5][6][3]>::value, false, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<UDT>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<void>::value, false);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<empty_POD_UDT>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<POD_UDT>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<POD_union_UDT>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<empty_POD_union_UDT>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<nothrow_copy_UDT>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<nothrow_assign_UDT>::value, true);
BOOST_CHECK_INTEGRAL_CONSTANT(::tt::is_copy_assignable<nothrow_construct_UDT>::value, true);
TT_TEST_END