1 // (C) Copyright 2009-2011 Frederic Bron, Robert Stewart, Steven Watanabe & Roman Perepelitsa. 2 // 3 // Use, modification and distribution are subject to the Boost Software License, 4 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt). 6 // 7 // See http://www.boost.org/libs/type_traits for most recent version including documentation. 8 9 #include <boost/config.hpp> 10 #include <boost/type_traits/detail/config.hpp> 11 12 #if defined(BOOST_TT_HAS_ACCURATE_BINARY_OPERATOR_DETECTION) 13 14 #include <boost/type_traits/integral_constant.hpp> 15 #include <boost/type_traits/make_void.hpp> 16 #include <boost/type_traits/is_convertible.hpp> 17 #include <boost/type_traits/is_void.hpp> 18 #include <boost/type_traits/add_reference.hpp> 19 #include <utility> 20 21 namespace boost 22 { 23 24 namespace binary_op_detail { 25 26 struct dont_care; 27 28 template <class T, class Ret, class = void> 29 struct BOOST_JOIN(BOOST_TT_TRAIT_NAME, _ret_imp) : public boost::false_type {}; 30 31 template <class T, class Ret> 32 struct BOOST_JOIN(BOOST_TT_TRAIT_NAME, _ret_imp)<T, Ret, typename boost::make_void<decltype(std::declval<typename add_reference<T>::type>() BOOST_TT_TRAIT_OP) >::type> 33 : public boost::integral_constant<bool, ::boost::is_convertible<decltype(std::declval<typename add_reference<T>::type>() BOOST_TT_TRAIT_OP), Ret>::value> {}; 34 35 template <class T, class = void > 36 struct BOOST_JOIN(BOOST_TT_TRAIT_NAME, _void_imp) : public boost::false_type {}; 37 38 template <class T> 39 struct BOOST_JOIN(BOOST_TT_TRAIT_NAME, _void_imp)<T, typename boost::make_void<decltype(std::declval<typename add_reference<T>::type>()BOOST_TT_TRAIT_OP)>::type> 40 : public boost::integral_constant<bool, ::boost::is_void<decltype(std::declval<typename add_reference<T>::type>() BOOST_TT_TRAIT_OP)>::value> {}; 41 42 template <class T, class = void> 43 struct BOOST_JOIN(BOOST_TT_TRAIT_NAME, _dc_imp) : public boost::false_type {}; 44 45 template <class T> 46 struct BOOST_JOIN(BOOST_TT_TRAIT_NAME, _dc_imp)<T, typename boost::make_void<decltype(std::declval<typename add_reference<T>::type>() BOOST_TT_TRAIT_OP)>::type> 47 : public boost::true_type {}; 48 49 } 50 51 template <class T, class Ret = boost::binary_op_detail::dont_care> 52 struct BOOST_TT_TRAIT_NAME : public boost::binary_op_detail::BOOST_JOIN(BOOST_TT_TRAIT_NAME, _ret_imp) <T, Ret> {}; 53 template <class T> 54 struct BOOST_TT_TRAIT_NAME<T, void> : public boost::binary_op_detail::BOOST_JOIN(BOOST_TT_TRAIT_NAME, _void_imp) <T> {}; 55 template <class T> 56 struct BOOST_TT_TRAIT_NAME<T, boost::binary_op_detail::dont_care> : public boost::binary_op_detail::BOOST_JOIN(BOOST_TT_TRAIT_NAME, _dc_imp) <T> {}; 57 58 59 } 60 61 #else 62 63 #include <boost/type_traits/detail/yes_no_type.hpp> 64 #include <boost/type_traits/integral_constant.hpp> 65 #include <boost/type_traits/is_const.hpp> 66 #include <boost/type_traits/is_fundamental.hpp> 67 #include <boost/type_traits/is_pointer.hpp> 68 #include <boost/type_traits/is_same.hpp> 69 #include <boost/type_traits/is_void.hpp> 70 #include <boost/type_traits/remove_cv.hpp> 71 #include <boost/type_traits/remove_pointer.hpp> 72 #include <boost/type_traits/remove_reference.hpp> 73 74 // avoid warnings 75 #if defined(__GNUC__) 76 # pragma GCC system_header 77 #elif defined(BOOST_MSVC) 78 # pragma warning ( push ) 79 # pragma warning ( disable : 4244 4913 4800) 80 # if BOOST_WORKAROUND(BOOST_MSVC_FULL_VER, >= 140050000) 81 # pragma warning ( disable : 6334) 82 # endif 83 #endif 84 85 namespace boost { 86 namespace detail { 87 88 // This namespace ensures that argument-dependent name lookup does not mess things up. 89 namespace BOOST_JOIN(BOOST_TT_TRAIT_NAME,_impl) { 90 91 // 1. a function to have an instance of type T without requiring T to be default 92 // constructible 93 template <typename T> T &make(); 94 95 96 // 2. we provide our operator definition for types that do not have one already 97 98 // a type returned from operator BOOST_TT_TRAIT_OP when no such operator is 99 // found in the type's own namespace (our own operator is used) so that we have 100 // a means to know that our operator was used 101 struct no_operator { }; 102 103 // this class allows implicit conversions and makes the following operator 104 // definition less-preferred than any other such operators that might be found 105 // via argument-dependent name lookup 106 struct any { template <class T> any(T const&); }; 107 108 // when operator BOOST_TT_TRAIT_OP is not available, this one is used 109 no_operator operator BOOST_TT_TRAIT_OP (const any&, int); 110 111 112 // 3. checks if the operator returns void or not 113 // conditions: Lhs!=void 114 115 // we first redefine "operator," so that we have no compilation error if 116 // operator BOOST_TT_TRAIT_OP returns void and we can use the return type of 117 // (lhs BOOST_TT_TRAIT_OP, returns_void_t()) to deduce if 118 // operator BOOST_TT_TRAIT_OP returns void or not: 119 // - operator BOOST_TT_TRAIT_OP returns void -> (lhs BOOST_TT_TRAIT_OP, returns_void_t()) returns returns_void_t 120 // - operator BOOST_TT_TRAIT_OP returns !=void -> (lhs BOOST_TT_TRAIT_OP, returns_void_t()) returns int 121 struct returns_void_t { }; 122 template <typename T> int operator,(const T&, returns_void_t); 123 template <typename T> int operator,(const volatile T&, returns_void_t); 124 125 // this intermediate trait has member value of type bool: 126 // - value==true -> operator BOOST_TT_TRAIT_OP returns void 127 // - value==false -> operator BOOST_TT_TRAIT_OP does not return void 128 template < typename Lhs > 129 struct operator_returns_void { 130 // overloads of function returns_void make the difference 131 // yes_type and no_type have different size by construction 132 static ::boost::type_traits::yes_type returns_void(returns_void_t); 133 static ::boost::type_traits::no_type returns_void(int); 134 BOOST_STATIC_CONSTANT(bool, value = (sizeof(::boost::type_traits::yes_type)==sizeof(returns_void((make<Lhs>() BOOST_TT_TRAIT_OP,returns_void_t()))))); 135 }; 136 137 138 // 4. checks if the return type is Ret or Ret==dont_care 139 // conditions: Lhs!=void 140 141 struct dont_care { }; 142 143 template < typename Lhs, typename Ret, bool Returns_void > 144 struct operator_returns_Ret; 145 146 template < typename Lhs > 147 struct operator_returns_Ret < Lhs, dont_care, true > { 148 BOOST_STATIC_CONSTANT(bool, value = true); 149 }; 150 151 template < typename Lhs > 152 struct operator_returns_Ret < Lhs, dont_care, false > { 153 BOOST_STATIC_CONSTANT(bool, value = true); 154 }; 155 156 template < typename Lhs > 157 struct operator_returns_Ret < Lhs, void, true > { 158 BOOST_STATIC_CONSTANT(bool, value = true); 159 }; 160 161 template < typename Lhs > 162 struct operator_returns_Ret < Lhs, void, false > { 163 BOOST_STATIC_CONSTANT(bool, value = false); 164 }; 165 166 template < typename Lhs, typename Ret > 167 struct operator_returns_Ret < Lhs, Ret, true > { 168 BOOST_STATIC_CONSTANT(bool, value = false); 169 }; 170 171 // otherwise checks if it is convertible to Ret using the sizeof trick 172 // based on overload resolution 173 // condition: Ret!=void and Ret!=dont_care and the operator does not return void 174 template < typename Lhs, typename Ret > 175 struct operator_returns_Ret < Lhs, Ret, false > { 176 static ::boost::type_traits::yes_type is_convertible_to_Ret(Ret); // this version is preferred for types convertible to Ret 177 static ::boost::type_traits::no_type is_convertible_to_Ret(...); // this version is used otherwise 178 179 BOOST_STATIC_CONSTANT(bool, value = (sizeof(is_convertible_to_Ret(make<Lhs>() BOOST_TT_TRAIT_OP))==sizeof(::boost::type_traits::yes_type))); 180 }; 181 182 183 // 5. checks for operator existence 184 // condition: Lhs!=void 185 186 // checks if our definition of operator BOOST_TT_TRAIT_OP is used or an other 187 // existing one; 188 // this is done with redefinition of "operator," that returns no_operator or has_operator 189 struct has_operator { }; 190 no_operator operator,(no_operator, has_operator); 191 192 template < typename Lhs > 193 struct operator_exists { 194 static ::boost::type_traits::yes_type s_check(has_operator); // this version is preferred when operator exists 195 static ::boost::type_traits::no_type s_check(no_operator); // this version is used otherwise 196 197 BOOST_STATIC_CONSTANT(bool, value = (sizeof(s_check(((make<Lhs>() BOOST_TT_TRAIT_OP),make<has_operator>())))==sizeof(::boost::type_traits::yes_type))); 198 }; 199 200 201 // 6. main trait: to avoid any compilation error, this class behaves 202 // differently when operator BOOST_TT_TRAIT_OP(Lhs) is forbidden by the 203 // standard. 204 // Forbidden_if is a bool that is: 205 // - true when the operator BOOST_TT_TRAIT_OP(Lhs) is forbidden by the standard 206 // (would yield compilation error if used) 207 // - false otherwise 208 template < typename Lhs, typename Ret, bool Forbidden_if > 209 struct trait_impl1; 210 211 template < typename Lhs, typename Ret > 212 struct trait_impl1 < Lhs, Ret, true > { 213 BOOST_STATIC_CONSTANT(bool, value = false); 214 }; 215 216 template < typename Lhs, typename Ret > 217 struct trait_impl1 < Lhs, Ret, false > { 218 BOOST_STATIC_CONSTANT(bool, 219 value = (operator_exists < Lhs >::value && operator_returns_Ret < Lhs, Ret, operator_returns_void < Lhs >::value >::value)); 220 }; 221 222 // specialization needs to be declared for the special void case 223 template < typename Ret > 224 struct trait_impl1 < void, Ret, false > { 225 BOOST_STATIC_CONSTANT(bool, value = false); 226 }; 227 228 // defines some typedef for convenience 229 template < typename Lhs, typename Ret > 230 struct trait_impl { 231 typedef typename ::boost::remove_reference<Lhs>::type Lhs_noref; 232 typedef typename ::boost::remove_cv<Lhs_noref>::type Lhs_nocv; 233 typedef typename ::boost::remove_cv< typename ::boost::remove_reference< typename ::boost::remove_pointer<Lhs_noref>::type >::type >::type Lhs_noptr; 234 BOOST_STATIC_CONSTANT(bool, value = (trait_impl1 < Lhs_noref, Ret, BOOST_TT_FORBIDDEN_IF >::value)); 235 }; 236 237 } // namespace impl 238 } // namespace detail 239 240 // this is the accessible definition of the trait to end user 241 template <class Lhs, class Ret=::boost::detail::BOOST_JOIN(BOOST_TT_TRAIT_NAME,_impl)::dont_care> 242 struct BOOST_TT_TRAIT_NAME : public integral_constant<bool, (::boost::detail::BOOST_JOIN(BOOST_TT_TRAIT_NAME, _impl)::trait_impl< Lhs, Ret >::value)>{}; 243 244 } // namespace boost 245 246 #if defined(BOOST_MSVC) 247 # pragma warning ( pop ) 248 #endif 249 250 #endif 251