Phi
is_convertible.hpp
1 #ifndef INCG_PHI_CORE_TYPE_TRAITS_IS_CONVERTIBLE_HPP
2 #define INCG_PHI_CORE_TYPE_TRAITS_IS_CONVERTIBLE_HPP
3 
4 #include "phi/phi_config.hpp"
5 
6 #if PHI_HAS_EXTENSION_PRAGMA_ONCE()
7 # pragma once
8 #endif
9 
10 #include "phi/compiler_support/constexpr.hpp"
11 #include "phi/compiler_support/inline_variables.hpp"
12 #include "phi/compiler_support/intrinsics/is_convertible.hpp"
13 #include "phi/type_traits/integral_constant.hpp"
14 
15 #if PHI_SUPPORTS_IS_CONVERTIBLE()
16 
17 DETAIL_PHI_BEGIN_NAMESPACE()
18 
19 template <typename FromT, typename ToT>
20 struct is_convertible : public integral_constant<bool, PHI_IS_CONVERTIBLE(FromT, ToT)>
21 {};
22 
23 template <typename FromT, typename ToT>
24 struct is_not_convertible : public integral_constant<bool, !PHI_IS_CONVERTIBLE(FromT, ToT)>
25 {};
26 
27 # if PHI_HAS_FEATURE_VARIABLE_TEMPLATE()
28 
29 template <typename FromT, typename ToT>
30 PHI_INLINE_VARIABLE PHI_CONSTEXPR bool is_convertible_v = PHI_IS_CONVERTIBLE(FromT, ToT);
31 
32 template <typename FromT, typename ToT>
33 PHI_INLINE_VARIABLE PHI_CONSTEXPR bool is_not_convertible_v = !PHI_IS_CONVERTIBLE(FromT, ToT);
34 
35 # endif
36 
37 #elif PHI_COMPILER_IS_NOT(MSVC)
38 
39 # include "phi/compiler_support/compiler.hpp"
40 # include "phi/compiler_support/warning.hpp"
41 # include "phi/core/declval.hpp"
42 # include "phi/type_traits/is_void.hpp"
43 
44 PHI_CLANG_SUPPRESS_WARNING_PUSH()
45 # if PHI_COMPILER_IS_ATLEAST(CLANG, 10, 0, 0) || PHI_COMPILER_IS_ATLEAST(APPLECLANG, 12, 0, 0)
46 PHI_CLANG_SUPPRESS_WARNING("-Wdeprecated-volatile")
47 # endif
48 
49 DETAIL_PHI_BEGIN_NAMESPACE()
50 
51 namespace detail
52 {
53  template <typename TypeT>
54  auto test_returnable(int)
55  -> decltype(static_cast<void>(static_cast<TypeT (*)()>(nullptr)), true_type{});
56 
57  template <typename>
58  auto test_returnable(...) -> false_type;
59 
60  template <typename FromT, typename ToT>
61  auto test_implicitly_convertible(int)
62  -> decltype(static_cast<void>(declval<void (&)(ToT)>()(declval<FromT>())), true_type{});
63 
64  template <typename, typename>
65  auto test_implicitly_convertible(...) -> false_type;
66 
67 } // namespace detail
68 
69 template <typename FromT, typename ToT>
70 struct is_convertible
71  : public integral_constant<bool, (decltype(detail::test_returnable<ToT>(0))::value &&
72  decltype(detail::test_implicitly_convertible<FromT, ToT>(
73  0))::value) ||
74  (is_void<FromT>::value && is_void<ToT>::value)>
75 {};
76 
77 template <typename FromT, typename ToT>
78 struct is_not_convertible : public integral_constant<bool, !is_convertible<FromT, ToT>::value>
79 {};
80 
81 PHI_CLANG_SUPPRESS_WARNING_POP()
82 
83 # if PHI_HAS_FEATURE_VARIABLE_TEMPLATE()
84 
85 template <typename FromT, typename ToT>
86 PHI_INLINE_VARIABLE PHI_CONSTEXPR bool is_convertible_v = is_convertible<FromT, ToT>::value;
87 
88 template <typename FromT, typename ToT>
89 PHI_INLINE_VARIABLE PHI_CONSTEXPR bool is_not_convertible_v = is_not_convertible<FromT, ToT>::value;
90 
91 # endif
92 
93 #else
94 
95 // Workaround implementation since the other version crashes the msvc compiler
96 
97 # include "phi/core/declval.hpp"
98 # include "phi/type_traits/is_array.hpp"
99 # include "phi/type_traits/is_function.hpp"
100 # include "phi/type_traits/is_void.hpp"
101 # include "phi/type_traits/remove_reference.hpp"
102 
103 DETAIL_PHI_BEGIN_NAMESPACE()
104 
105 namespace detail
106 {
107  template <typename TypeT>
108  void test_convert(TypeT);
109 
110  template <typename FromT, typename ToT, typename = void>
112  {};
113 
114  template <typename FromT, typename ToT>
115  struct is_convertible_impl_test<FromT, ToT,
116  decltype(detail::test_convert<ToT>(declval<FromT>()))>
117  : public true_type
118  {};
119 
120  template <typename TypeT, bool IsArray = is_array<TypeT>::value,
121  bool IsFunction = is_function<TypeT>::value, bool IsVoid = is_void<TypeT>::value>
123  {
124  enum
125  {
126  value = 0
127  };
128  };
129 
130  template <typename TypeT>
131  struct is_array_function_or_void<TypeT, true, false, false>
132  {
133  enum
134  {
135  value = 1
136  };
137  };
138 
139  template <typename TypeT>
140  struct is_array_function_or_void<TypeT, false, true, false>
141  {
142  enum
143  {
144  value = 2
145  };
146  };
147 
148  template <typename TypeT>
149  struct is_array_function_or_void<TypeT, false, false, true>
150  {
151  enum
152  {
153  value = 3
154  };
155  };
156  template <typename TypeT, unsigned = detail::is_array_function_or_void<
157  typename remove_reference<TypeT>::type>::value>
159  {
160  static const size_t value = 0;
161  };
162 
163  template <typename TypeT>
164  struct is_convertible_check<TypeT, 0>
165  {
166  static const size_t value = sizeof(TypeT);
167  };
168 
169  template <typename FromT, typename ToT,
170  unsigned FromTIsArrayFunctionOrVoid = detail::is_array_function_or_void<FromT>::value,
171  unsigned ToTIsArrayFunctionOrVoid = detail::is_array_function_or_void<ToT>::value>
173  : public integral_constant<bool, detail::is_convertible_impl_test<FromT, ToT>::value>
174  {};
175 
176  template <typename FromT, typename ToT>
177  struct is_convertible_impl<FromT, ToT, 0, 1> : public false_type
178  {};
179  template <typename FromT, typename ToT>
180  struct is_convertible_impl<FromT, ToT, 1, 1> : public false_type
181  {};
182  template <typename FromT, typename ToT>
183  struct is_convertible_impl<FromT, ToT, 2, 1> : public false_type
184  {};
185  template <typename FromT, typename ToT>
186  struct is_convertible_impl<FromT, ToT, 3, 1> : public false_type
187  {};
188 
189  template <typename FromT, typename ToT>
190  struct is_convertible_impl<FromT, ToT, 0, 2> : public false_type
191  {};
192  template <typename FromT, typename ToT>
193  struct is_convertible_impl<FromT, ToT, 1, 2> : public false_type
194  {};
195  template <typename FromT, typename ToT>
196  struct is_convertible_impl<FromT, ToT, 2, 2> : public false_type
197  {};
198  template <typename FromT, typename ToT>
199  struct is_convertible_impl<FromT, ToT, 3, 2> : public false_type
200  {};
201 
202  template <typename FromT, typename ToT>
203  struct is_convertible_impl<FromT, ToT, 0, 3> : public false_type
204  {};
205  template <typename FromT, typename ToT>
206  struct is_convertible_impl<FromT, ToT, 1, 3> : public false_type
207  {};
208  template <typename FromT, typename ToT>
209  struct is_convertible_impl<FromT, ToT, 2, 3> : public false_type
210  {};
211  template <typename FromT, typename ToT>
212  struct is_convertible_impl<FromT, ToT, 3, 3> : public true_type
213  {};
214 } // namespace detail
215 
216 template <typename FromT, typename ToT>
217 struct is_convertible : public detail::is_convertible_impl<FromT, ToT>
218 {
219 private:
220  static PHI_CONSTEXPR_AND_CONST size_t complete_check_from_t =
222  static PHI_CONSTEXPR_AND_CONST size_t complete_check_to_t =
224 };
225 
226 template <typename FromT, typename ToT>
227 struct is_not_convertible : public integral_constant<bool, !is_convertible<FromT, ToT>::value>
228 {};
229 
230 PHI_CLANG_SUPPRESS_WARNING_POP()
231 
232 # if PHI_HAS_FEATURE_VARIABLE_TEMPLATE()
233 
234 template <typename FromT, typename ToT>
235 PHI_INLINE_VARIABLE PHI_CONSTEXPR bool is_convertible_v = is_convertible<FromT, ToT>::value;
236 
237 template <typename FromT, typename ToT>
238 PHI_INLINE_VARIABLE PHI_CONSTEXPR bool is_not_convertible_v = is_not_convertible<FromT, ToT>::value;
239 
240 # endif
241 
242 #endif
243 
244 DETAIL_PHI_END_NAMESPACE()
245 
246 #endif // INCG_PHI_CORE_TYPE_TRAITS_IS_CONVERTIBLE_HPP
Definition: integral_constant.hpp:19
Definition: is_convertible.hpp:122
Definition: is_convertible.hpp:158
Definition: is_convertible.hpp:111
Definition: is_function.hpp:45
Definition: is_convertible.hpp:217
Definition: swap.hpp:23
Definition: is_convertible.hpp:172
Definition: is_convertible.hpp:227
Definition: is_void.hpp:17