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 #ifdef BOOST_GCC 22 #pragma GCC diagnostic push 23 #pragma GCC diagnostic ignored "-Wdeprecated" 24 #endif 25 #if defined(BOOST_MSVC) 26 # pragma warning ( push ) 27 # pragma warning ( disable : 4804) 28 #endif 29 30 namespace boost 31 { 32 33 namespace binary_op_detail { 34 35 struct dont_care; 36 37 template <class T, class Ret, class = void> 38 struct BOOST_JOIN(BOOST_TT_TRAIT_NAME, _ret_imp) : public boost::false_type {}; 39 40 template <class T, class Ret> 41 struct BOOST_JOIN(BOOST_TT_TRAIT_NAME, _ret_imp)<T, Ret, typename boost::make_void<decltype(BOOST_TT_TRAIT_OP std::declval<typename add_reference<T>::type>()) >::type> 42 : public boost::integral_constant<bool, ::boost::is_convertible<decltype(BOOST_TT_TRAIT_OP std::declval<typename add_reference<T>::type>() ), Ret>::value> {}; 43 44 template <class T, class = void > 45 struct BOOST_JOIN(BOOST_TT_TRAIT_NAME, _void_imp) : public boost::false_type {}; 46 47 template <class T> 48 struct BOOST_JOIN(BOOST_TT_TRAIT_NAME, _void_imp)<T, typename boost::make_void<decltype(BOOST_TT_TRAIT_OP std::declval<typename add_reference<T>::type>())>::type> 49 : public boost::integral_constant<bool, ::boost::is_void<decltype(BOOST_TT_TRAIT_OP std::declval<typename add_reference<T>::type>())>::value> {}; 50 51 template <class T, class = void> 52 struct BOOST_JOIN(BOOST_TT_TRAIT_NAME, _dc_imp) : public boost::false_type {}; 53 54 template <class T> 55 struct BOOST_JOIN(BOOST_TT_TRAIT_NAME, _dc_imp)<T, typename boost::make_void<decltype(BOOST_TT_TRAIT_OP std::declval<typename add_reference<T>::type>() )>::type> 56 : public boost::true_type {}; 57 58 } 59 60 template <class T, class Ret = boost::binary_op_detail::dont_care> 61 struct BOOST_TT_TRAIT_NAME : public boost::binary_op_detail::BOOST_JOIN(BOOST_TT_TRAIT_NAME, _ret_imp) <T, Ret> {}; 62 template <class T> 63 struct BOOST_TT_TRAIT_NAME<T, void> : public boost::binary_op_detail::BOOST_JOIN(BOOST_TT_TRAIT_NAME, _void_imp) <T> {}; 64 template <class T> 65 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> {}; 66 67 68 } 69 70 #ifdef BOOST_GCC 71 #pragma GCC diagnostic pop 72 #endif 73 #if defined(BOOST_MSVC) 74 # pragma warning ( pop ) 75 #endif 76 77 #else 78 79 #include <boost/type_traits/detail/yes_no_type.hpp> 80 #include <boost/type_traits/integral_constant.hpp> 81 #include <boost/type_traits/is_const.hpp> 82 #include <boost/type_traits/is_fundamental.hpp> 83 #include <boost/type_traits/is_integral.hpp> 84 #include <boost/type_traits/is_pointer.hpp> 85 #include <boost/type_traits/is_same.hpp> 86 #include <boost/type_traits/is_void.hpp> 87 #include <boost/type_traits/remove_cv.hpp> 88 #include <boost/type_traits/remove_pointer.hpp> 89 #include <boost/type_traits/remove_reference.hpp> 90 91 // cannot include this header without getting warnings of the kind: 92 // gcc: 93 // warning: value computed is not used 94 // warning: comparison between signed and unsigned integer expressions 95 // msvc: 96 // warning C4146: unary minus operator applied to unsigned type, result still unsigned 97 // warning C4804: '-' : unsafe use of type 'bool' in operation 98 // cannot find another implementation -> declared as system header to suppress these warnings. 99 #if defined(__GNUC__) 100 # pragma GCC system_header 101 #elif defined(BOOST_MSVC) 102 # pragma warning ( push ) 103 # pragma warning ( disable : 4146 4804 4913 4244 4800) 104 # if BOOST_WORKAROUND(BOOST_MSVC_FULL_VER, >= 140050000) 105 # pragma warning ( disable : 6334) 106 # endif 107 # if BOOST_WORKAROUND(_MSC_VER, >= 1913) 108 # pragma warning ( disable : 4834) 109 # endif 110 #endif 111 112 113 114 namespace boost { 115 namespace detail { 116 117 // This namespace ensures that argument-dependent name lookup does not mess things up. 118 namespace BOOST_JOIN(BOOST_TT_TRAIT_NAME,_impl) { 119 120 // 1. a function to have an instance of type T without requiring T to be default 121 // constructible 122 template <typename T> T &make(); 123 124 125 // 2. we provide our operator definition for types that do not have one already 126 127 // a type returned from operator BOOST_TT_TRAIT_OP when no such operator is 128 // found in the type's own namespace (our own operator is used) so that we have 129 // a means to know that our operator was used 130 struct no_operator { }; 131 132 // this class allows implicit conversions and makes the following operator 133 // definition less-preferred than any other such operators that might be found 134 // via argument-dependent name lookup 135 struct any { template <class T> any(T const&); }; 136 137 // when operator BOOST_TT_TRAIT_OP is not available, this one is used 138 no_operator operator BOOST_TT_TRAIT_OP (const any&); 139 140 141 // 3. checks if the operator returns void or not 142 // conditions: Rhs!=void 143 144 // we first redefine "operator," so that we have no compilation error if 145 // operator BOOST_TT_TRAIT_OP returns void and we can use the return type of 146 // (BOOST_TT_TRAIT_OP rhs, returns_void_t()) to deduce if 147 // operator BOOST_TT_TRAIT_OP returns void or not: 148 // - operator BOOST_TT_TRAIT_OP returns void -> (BOOST_TT_TRAIT_OP rhs, returns_void_t()) returns returns_void_t 149 // - operator BOOST_TT_TRAIT_OP returns !=void -> (BOOST_TT_TRAIT_OP rhs, returns_void_t()) returns int 150 struct returns_void_t { }; 151 template <typename T> int operator,(const T&, returns_void_t); 152 template <typename T> int operator,(const volatile T&, returns_void_t); 153 154 // this intermediate trait has member value of type bool: 155 // - value==true -> operator BOOST_TT_TRAIT_OP returns void 156 // - value==false -> operator BOOST_TT_TRAIT_OP does not return void 157 template < typename Rhs > 158 struct operator_returns_void { 159 // overloads of function returns_void make the difference 160 // yes_type and no_type have different size by construction 161 static ::boost::type_traits::yes_type returns_void(returns_void_t); 162 static ::boost::type_traits::no_type returns_void(int); 163 BOOST_STATIC_CONSTANT(bool, value = (sizeof(::boost::type_traits::yes_type)==sizeof(returns_void((BOOST_TT_TRAIT_OP make<Rhs>(),returns_void_t()))))); 164 }; 165 166 167 // 4. checks if the return type is Ret or Ret==dont_care 168 // conditions: Rhs!=void 169 170 struct dont_care { }; 171 172 template < typename Rhs, typename Ret, bool Returns_void > 173 struct operator_returns_Ret; 174 175 template < typename Rhs > 176 struct operator_returns_Ret < Rhs, dont_care, true > { 177 BOOST_STATIC_CONSTANT(bool, value = true); 178 }; 179 180 template < typename Rhs > 181 struct operator_returns_Ret < Rhs, dont_care, false > { 182 BOOST_STATIC_CONSTANT(bool, value = true); 183 }; 184 185 template < typename Rhs > 186 struct operator_returns_Ret < Rhs, void, true > { 187 BOOST_STATIC_CONSTANT(bool, value = true); 188 }; 189 190 template < typename Rhs > 191 struct operator_returns_Ret < Rhs, void, false > { 192 BOOST_STATIC_CONSTANT(bool, value = false); 193 }; 194 195 template < typename Rhs, typename Ret > 196 struct operator_returns_Ret < Rhs, Ret, true > { 197 BOOST_STATIC_CONSTANT(bool, value = false); 198 }; 199 200 // otherwise checks if it is convertible to Ret using the sizeof trick 201 // based on overload resolution 202 // condition: Ret!=void and Ret!=dont_care and the operator does not return void 203 template < typename Rhs, typename Ret > 204 struct operator_returns_Ret < Rhs, Ret, false > { 205 static ::boost::type_traits::yes_type is_convertible_to_Ret(Ret); // this version is preferred for types convertible to Ret 206 static ::boost::type_traits::no_type is_convertible_to_Ret(...); // this version is used otherwise 207 208 BOOST_STATIC_CONSTANT(bool, value = (sizeof(is_convertible_to_Ret(BOOST_TT_TRAIT_OP make<Rhs>()))==sizeof(::boost::type_traits::yes_type))); 209 }; 210 211 212 // 5. checks for operator existence 213 // condition: Rhs!=void 214 215 // checks if our definition of operator BOOST_TT_TRAIT_OP is used or an other 216 // existing one; 217 // this is done with redefinition of "operator," that returns no_operator or has_operator 218 struct has_operator { }; 219 no_operator operator,(no_operator, has_operator); 220 221 template < typename Rhs > 222 struct operator_exists { 223 static ::boost::type_traits::yes_type s_check(has_operator); // this version is preferred when operator exists 224 static ::boost::type_traits::no_type s_check(no_operator); // this version is used otherwise 225 226 BOOST_STATIC_CONSTANT(bool, value = (sizeof(s_check(((BOOST_TT_TRAIT_OP make<Rhs>()),make<has_operator>())))==sizeof(::boost::type_traits::yes_type))); 227 }; 228 229 230 // 6. main trait: to avoid any compilation error, this class behaves 231 // differently when operator BOOST_TT_TRAIT_OP(Rhs) is forbidden by the 232 // standard. 233 // Forbidden_if is a bool that is: 234 // - true when the operator BOOST_TT_TRAIT_OP(Rhs) is forbidden by the standard 235 // (would yield compilation error if used) 236 // - false otherwise 237 template < typename Rhs, typename Ret, bool Forbidden_if > 238 struct trait_impl1; 239 240 template < typename Rhs, typename Ret > 241 struct trait_impl1 < Rhs, Ret, true > { 242 BOOST_STATIC_CONSTANT(bool, value = false); 243 }; 244 245 template < typename Rhs, typename Ret > 246 struct trait_impl1 < Rhs, Ret, false > { 247 BOOST_STATIC_CONSTANT(bool, 248 value = (operator_exists < Rhs >::value && operator_returns_Ret < Rhs, Ret, operator_returns_void < Rhs >::value >::value)); 249 }; 250 251 // specialization needs to be declared for the special void case 252 template < typename Ret > 253 struct trait_impl1 < void, Ret, false > { 254 BOOST_STATIC_CONSTANT(bool, value = false); 255 }; 256 257 // defines some typedef for convenience 258 template < typename Rhs, typename Ret > 259 struct trait_impl { 260 typedef typename ::boost::remove_reference<Rhs>::type Rhs_noref; 261 typedef typename ::boost::remove_cv<Rhs_noref>::type Rhs_nocv; 262 typedef typename ::boost::remove_cv< typename ::boost::remove_reference< typename ::boost::remove_pointer<Rhs_noref>::type >::type >::type Rhs_noptr; 263 BOOST_STATIC_CONSTANT(bool, value = (trait_impl1 < Rhs_noref, Ret, BOOST_TT_FORBIDDEN_IF >::value)); 264 }; 265 266 } // namespace impl 267 } // namespace detail 268 269 // this is the accessible definition of the trait to end user 270 template <class Rhs, class Ret=::boost::detail::BOOST_JOIN(BOOST_TT_TRAIT_NAME,_impl)::dont_care> 271 struct BOOST_TT_TRAIT_NAME : public integral_constant<bool, (::boost::detail::BOOST_JOIN(BOOST_TT_TRAIT_NAME, _impl)::trait_impl < Rhs, Ret >::value)>{}; 272 273 } // namespace boost 274 275 #if defined(BOOST_MSVC) 276 # pragma warning ( pop ) 277 #endif 278 279 #endif 280 281