Finite Volume Solver  prototype
A framework to build finite volume solvers for the AG Klein at the Freie Universität Berlin.
type_traits.hpp
Go to the documentation of this file.
1 // Copyright (c) 2017 Maikel Nadolski
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 // SOFTWARE.
20 
21 /// @file type_traits.hpp This file adds basic type traits utilities which are
22 /// not yet implemented in all standard libraries.
23 
24 #ifndef FUB_CORE_TYPE_TRAITS_HPP
25 #define FUB_CORE_TYPE_TRAITS_HPP
26 
27 #include <type_traits>
28 #include <utility>
29 
30 /// \brief The fub namespace
31 namespace fub {
32 #if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603
33 using std::byte;
34 #else
35 using byte = unsigned char;
36 #endif
37 
38 ////////////////////////////////////////////////////////////////////////////////
39 // [traits.is_detected]
40 
41 /// \defgroup type-traits Type Traits
42 /// Type traits are used to enforce requirements on types with SFINAE.
43 
44 template <class...> using void_t = void;
45 
46 template <typename T> struct nodeduce { using type = T; };
47 template <typename T> using nodeduce_t = typename nodeduce<T>::type;
48 
49 struct nonesuch {
50  nonesuch() = delete;
51  ~nonesuch() = delete;
52  nonesuch(nonesuch const&) = delete;
53  void operator=(nonesuch const&) = delete;
54 };
55 
56 namespace detail {
57 template <class Default, class AlwaysVoid, template <class...> class Op,
58  class... Args>
59 struct detector {
60  using value_t = std::false_type;
61  using type = Default;
62 };
63 
64 template <class Default, template <class...> class Op, class... Args>
65 struct detector<Default, void_t<Op<Args...>>, Op, Args...> {
66  using value_t = std::true_type;
67  using type = Op<Args...>;
68 };
69 
70 template <template <class...> class Op, class... Args>
71 using is_detected =
72  typename detail::detector<nonesuch, void, Op, Args...>::value_t;
73 
74 /// \ingroup type-traits
75 /// Returns the type of `Op<Args...>` or `nonesuch`
76 template <template <class...> class Op, class... Args>
77 using detected_t = typename detail::detector<nonesuch, void, Op, Args...>::type;
78 
79 template <class Default, template <class...> class Op, class... Args>
80 using detected_or = detail::detector<Default, void, Op, Args...>;
81 
82 template <class Default, template <class...> class Op, class... Args>
83 using detected_or_t = typename detected_or<Default, Op, Args...>::type;
84 
85 template <class Expected, template <typename...> class Op, class... Args>
86 using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
87 } // namespace detail
88 
89 /// \ingroup type-traits
90 /// This is `std::true_type` if `Op<Args...>` is a valid SFINAE expression.
91 template <template <class...> class Op, class... Args>
92 struct is_detected : detail::is_detected<Op, Args...> {};
93 
94 /// \ingroup type-traits
95 /// Returns the type of `Op<Args...>` or `nonesuch`
96 template <template <class...> class Op, class... Args>
97 using detected_t = detail::detected_t<Op, Args...>;
98 
99 /// \ingroup type-traits
100 /// Returns the type of `Op<Args...>` or `Default`
101 template <class Default, template <class...> class Op, class... Args>
102 struct detected_or : detail::detected_or<Default, Op, Args...> {};
103 
104 /// \ingroup type-traits
105 /// This is `std::true_type` if `Op<Args...>` is a valid SFINAE expression and
106 /// the return type is exactly `Expected`.
107 template <class Expected, template <typename...> class Op, class... Args>
108 struct is_detected_exact : detail::is_detected_exact<Expected, Op, Args...> {};
109 
110 ////////////////////////////////////////////////////////////////////////////////
111 // [traits.conjunction]
112 // [traits.disjunction]
113 // [traits.negation]
114 #if defined(__cpp_lib_logical_traits)
115 using std::conjunction;
116 using std::disjunction;
117 using std::negation;
118 #elif defined(__cpp_lib_experimental_logical_traits)
119 using std::experimental::conjunction;
120 using std::experimental::disjunction;
122 #else
123 template <class...> struct conjunction : std::true_type {};
124 template <class B1> struct conjunction<B1> : B1 {};
125 template <class B1, class... Bn>
126 struct conjunction<B1, Bn...>
127  : std::conditional_t<bool(B1::value), conjunction<Bn...>, B1> {};
128 
129 template <class...> struct disjunction : std::false_type {};
130 template <class B1> struct disjunction<B1> : B1 {};
131 template <class B1, class... Bn>
132 struct disjunction<B1, Bn...>
133  : std::conditional_t<bool(B1::value), B1, disjunction<Bn...>> {};
134 
135 template <class Bool>
136 using negation = std::integral_constant<bool, !bool(Bool::value)>;
137 #endif
138 
139 #if defined(__cpp_nontype_template_parameter_auto)
140 template <auto N> struct constant : std::integral_constant<decltype(N), N> {};
141 #endif
142 
143 #if defined(__cpp_lib_integer_sequence)
144 using std::index_sequence;
145 using std::integer_sequence;
148 #else
149 template <typename T, T... Ints> struct integer_sequence {
150  using value_type = T;
151 
152  static constexpr std::size_t size() noexcept { return sizeof...(Ints); }
153 };
154 
155 template <std::size_t... Is>
156 using index_sequence = integer_sequence<std::size_t, Is...>;
157 
158 template <typename T, T N, T Last, T... Ints> struct MakeIntegerSequence_;
159 
160 template <typename T, T N, T... Ints>
161 struct MakeIntegerSequence_<T, N, N, Ints...> {
162  using type = integer_sequence<T, Ints...>;
163 };
164 
165 template <typename T, T N, T L, T... Ints> struct MakeIntegerSequence_ {
166  using type = typename MakeIntegerSequence_<T, N, L + 1, Ints..., L>::type;
167 };
168 
169 template <typename T, T N>
170 using make_integer_sequence = typename MakeIntegerSequence_<T, N, T{0}>::type;
171 
172 template <std::size_t N>
174 #endif
175 
176 ////////////////////////////////////////////////////////////////////////////////
177 // [meta.constant]
178 
179 using index = std::ptrdiff_t;
180 
181 template <bool Bool> using bool_constant = std::integral_constant<bool, Bool>;
182 template <index I> using index_constant = std::integral_constant<index, I>;
183 template <int I> using int_constant = std::integral_constant<int, I>;
184 template <std::size_t I>
185 using size_constant = std::integral_constant<std::size_t, I>;
186 template <int I> static constexpr int_constant<I> int_c{};
187 template <bool B> static constexpr bool_constant<B> bool_c{};
188 template <index I> static constexpr index_constant<I> index_c{};
189 template <std::size_t I> static constexpr size_constant<I> size_c{};
190 
191 ////////////////////////////////////////////////////////////////////////////////
192 // [traits.is_invocable]
193 // [traits.invoke_result]
194 
195 #ifdef __cpp_lib_is_invocable
196 using std::invoke_result;
198 using std::is_invocable;
199 #else
200 /// \ingroup type-traits
201 /// This is `std::true_type` if `F` is a function type and can be invoked with
202 /// arguments of types `Args...`.
203 /// @{
204 template <typename F, typename... Args>
205 struct invoke_result : std::result_of<F(Args...)> {};
206 
207 template <typename F, typename... Args>
208 using invoke_result_t = typename invoke_result<F, Args...>::type;
209 /// @}
210 
211 /// \ingroup type-traits
212 /// This is `std::true_type` if a given object `f` of type `T` is callable by
213 /// `fub::invoke(f, args...)` for `Args... args`.
214 template <typename F, typename... Args>
215 struct is_invocable : is_detected<invoke_result_t, F, Args...> {};
216 #endif
217 
218 ////////////////////////////////////////////////////////////////////////////////
219 // [traits.remove_cvref]
220 
221 /// \ingroup type-traits
222 /// This is equivalent to `std::remove_cv_t<std::remove_reference_t<T>>`.
223 template <typename T> struct remove_cvref {
224  using type = std::remove_cv_t<std::remove_reference_t<T>>;
225 };
226 template <typename T> using remove_cvref_t = typename remove_cvref<T>::type;
227 
228 ////////////////////////////////////////////////////////////////////////////////
229 // [meta.value_type]
230 
231 template <typename Var> struct value_type {
232  using type = typename Var::value_type;
233 };
234 template <typename Var> using value_type_t = typename value_type<Var>::type;
235 
236 ////////////////////////////////////////////////////////////////////////////////
237 // [traits.is_equality_comparable]
238 // [traits.is_nothrow_equality_comparable]
239 
240 template <typename T, typename S = T> struct is_equality_comparable_impl {
241  template <typename L, typename R>
242  using equality_t = decltype(std::declval<L>() == std::declval<R>());
243 
244  template <typename L, typename R>
245  using inequality_t = decltype(std::declval<L>() != std::declval<R>());
246 
249 };
250 
251 /// \ingroup type-traits
252 /// This is `std::true_type` if `T` and `S` are equality comparable.
253 template <typename T, typename S = T>
255 
256 namespace detail {
257 template <typename T, typename S, bool IsComparable>
258 struct is_nothrow_equality_comparable_impl : bool_constant<false> {};
259 
260 template <typename T, typename S>
261 struct is_nothrow_equality_comparable_impl<T, S, true> {
262  static constexpr bool is_nothrow_equal =
263  noexcept(std::declval<T>() == std::declval<S>());
264 
265  static constexpr bool is_nothrow_inequal =
266  noexcept(std::declval<T>() != std::declval<S>());
267 
268  static constexpr bool value = is_nothrow_equal && is_nothrow_inequal;
269 };
270 } // namespace detail
271 
272 /// \ingroup type-traits
273 /// This is `std::true_type` if `T` and `S` are nothrow equality comparable.
274 template <typename T, typename S = T> struct is_nothrow_equality_comparable {
275  static constexpr bool value = detail::is_nothrow_equality_comparable_impl<
277 };
278 
279 ////////////////////////////////////////////////////////////////////////////////
280 // [traits.is_regular]
281 
282 /// \ingroup type-traits
283 /// This type trait checks if a specified type `T` fulfills the Regular concept.
284 template <typename T>
286  : conjunction<std::is_default_constructible<T>, std::is_copy_assignable<T>,
287  is_equality_comparable<T>> {};
288 
289 // helper type for the visitor #4
290 //#ifdef __cpp_deduction_guides
291 template <class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
292 template <class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
293 //#endif
294 
295 template <typename X, typename Y>
296 using decays_to = std::is_same<std::decay_t<X>, Y>;
297 
298 namespace meta {
299 namespace tag_invoke_fn {
300 template <typename Tag, typename... Args>
302  decltype(tag_invoke(std::declval<Tag>(), std::declval<Args>()...));
303 
305  template <typename Tag, typename... Args,
306  typename = std::enable_if_t<
307  is_detected<tag_invoke_t, Tag, Args...>::value>>
308  constexpr auto operator()(Tag&& tag, Args&&... args) const
309  noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
310  std::forward<Args>(args)...))) {
311  return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
312  }
313 };
314 } // namespace tag_invoke_fn
315 
316 inline namespace tag_invoke_ns {
318 }
319 }
320 
321 template <typename _Tag, typename... _Args>
323  : is_invocable<decltype(fub::meta::tag_invoke), _Tag, _Args...> {};
324 
325 namespace detail {
326 template <bool IsComparable, typename T, typename... Args>
327 struct is_nothrow_tag_invocable_impl : bool_constant<false> {};
328 
329 template <typename T, typename... Args>
330 struct is_nothrow_tag_invocable_impl<true, T, Args...> {
331  static constexpr bool value =
332  noexcept(fub::meta::tag_invoke(std::declval<T>(), std::declval<Args>()...));
333 };
334 } // namespace detail
335 
336 template <typename Tag, typename... Args>
338  : bool_constant<detail::is_nothrow_tag_invocable_impl<
339  is_tag_invocable<Tag, Args...>::value, Tag, Args...>::value> {};
340 
341 template <typename _Tag, typename... _Args>
343  invoke_result<decltype(fub::meta::tag_invoke), _Tag, _Args...>;
344 
345 template <typename _Tag, typename... _Args>
347  invoke_result_t<decltype(fub::meta::tag_invoke), _Tag, _Args...>;
348 
349 template <auto& T>
350 using tag_t = std::decay_t<decltype(T)>;
351 
352 } // namespace fub
353 
354 #endif // !TYPE_TRAITS_HPP
detail::detected_t< Op, Args... > detected_t
Returns the type of Op<Args...> or nonesuch
Definition: type_traits.hpp:97
decltype(tag_invoke(std::declval< Tag >(), std::declval< Args >()...)) tag_invoke_t
Definition: type_traits.hpp:302
constexpr tag_invoke_fn::tag_invoke_fn tag_invoke
Definition: type_traits.hpp:317
The fub namespace.
Definition: AnyBoundaryCondition.hpp:31
typename remove_cvref< T >::type remove_cvref_t
Definition: type_traits.hpp:226
integer_sequence< std::size_t, Is... > index_sequence
Definition: type_traits.hpp:156
std::integral_constant< bool, !bool(Bool::value)> negation
Definition: type_traits.hpp:136
invoke_result_t< decltype(fub::meta::tag_invoke), _Tag, _Args... > tag_invoke_result_t
Definition: type_traits.hpp:347
void void_t
Definition: type_traits.hpp:44
make_integer_sequence< std::size_t, N > make_index_sequence
Definition: type_traits.hpp:173
typename nodeduce< T >::type nodeduce_t
Definition: type_traits.hpp:47
std::decay_t< decltype(T)> tag_t
Definition: type_traits.hpp:350
typename invoke_result< F, Args... >::type invoke_result_t
Definition: type_traits.hpp:208
static constexpr bool_constant< B > bool_c
Definition: type_traits.hpp:187
typename value_type< Var >::type value_type_t
Definition: type_traits.hpp:234
std::integral_constant< bool, Bool > bool_constant
Definition: type_traits.hpp:181
static constexpr int_constant< I > int_c
Definition: type_traits.hpp:186
static constexpr size_constant< I > size_c
Definition: type_traits.hpp:189
std::integral_constant< std::size_t, I > size_constant
Definition: type_traits.hpp:185
typename MakeIntegerSequence_< T, N, T{0}>::type make_integer_sequence
Definition: type_traits.hpp:170
unsigned char byte
Definition: type_traits.hpp:35
static constexpr index_constant< I > index_c
Definition: type_traits.hpp:188
std::integral_constant< index, I > index_constant
Definition: type_traits.hpp:182
std::is_same< std::decay_t< X >, Y > decays_to
Definition: type_traits.hpp:296
overloaded(Ts...) -> overloaded< Ts... >
std::integral_constant< int, I > int_constant
Definition: type_traits.hpp:183
std::ptrdiff_t index
Definition: type_traits.hpp:179
Definition: type_traits.hpp:165
typename MakeIntegerSequence_< T, N, L+1, Ints..., L >::type type
Definition: type_traits.hpp:166
Definition: type_traits.hpp:124
Definition: type_traits.hpp:123
Returns the type of Op<Args...> or Default
Definition: type_traits.hpp:102
Definition: type_traits.hpp:130
Definition: type_traits.hpp:129
Definition: type_traits.hpp:149
T value_type
Definition: type_traits.hpp:150
static constexpr std::size_t size() noexcept
Definition: type_traits.hpp:152
This is std::true_type if F is a function type and can be invoked with arguments of types Args....
Definition: type_traits.hpp:205
This is std::true_type if Op<Args...> is a valid SFINAE expression and the return type is exactly Exp...
Definition: type_traits.hpp:108
This is std::true_type if Op<Args...> is a valid SFINAE expression.
Definition: type_traits.hpp:92
Definition: type_traits.hpp:240
decltype(std::declval< L >() !=std::declval< R >()) inequality_t
Definition: type_traits.hpp:245
decltype(std::declval< L >()==std::declval< R >()) equality_t
Definition: type_traits.hpp:242
This is std::true_type if T and S are equality comparable.
Definition: type_traits.hpp:254
This is std::true_type if a given object f of type T is callable by fub::invoke(f,...
Definition: type_traits.hpp:215
This is std::true_type if T and S are nothrow equality comparable.
Definition: type_traits.hpp:274
static constexpr bool value
Definition: type_traits.hpp:275
Definition: type_traits.hpp:339
This type trait checks if a specified type T fulfills the Regular concept.
Definition: type_traits.hpp:287
Definition: type_traits.hpp:323
Definition: type_traits.hpp:304
constexpr auto operator()(Tag &&tag, Args &&... args) const noexcept(noexcept(tag_invoke(std::forward< Tag >(tag), std::forward< Args >(args)...)))
Definition: type_traits.hpp:308
Definition: type_traits.hpp:46
T type
Definition: type_traits.hpp:46
Definition: type_traits.hpp:49
nonesuch()=delete
nonesuch(nonesuch const &)=delete
~nonesuch()=delete
void operator=(nonesuch const &)=delete
Definition: type_traits.hpp:291
This is equivalent to std::remove_cv_t<std::remove_reference_t<T>>.
Definition: type_traits.hpp:223
std::remove_cv_t< std::remove_reference_t< T > > type
Definition: type_traits.hpp:224
Definition: type_traits.hpp:231
typename Var::value_type type
Definition: type_traits.hpp:232