MongoDB C++ Driver 4.5.0
Loading...
Searching...
No Matches
type_traits.hpp
Go to the documentation of this file.
1// Copyright 2009-present MongoDB, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#pragma once
16
18
20
21#include <cstddef>
22#include <type_traits> // IWYU pragma: export
23#include <utility>
24
25namespace bsoncxx {
26namespace detail {
27
28// Obtain the nested ::type of the given type argument
29template <typename T>
30using type_t = typename T::type;
31
32// Obtain the value_type member type of the given argument
33template <typename T>
34using value_type_t = typename T::value_type;
35
36template <bool B, typename T = void>
37using enable_if_t = typename std::enable_if<B, T>::type;
38
39#pragma push_macro("DECL_ALIAS")
40#undef DECL_ALIAS
41#define DECL_ALIAS(Name) \
42 template <typename T> \
43 using Name##_t = type_t<std::Name<T>>
44DECL_ALIAS(decay);
45DECL_ALIAS(make_signed);
46DECL_ALIAS(make_unsigned);
47DECL_ALIAS(remove_reference);
48DECL_ALIAS(remove_const);
49DECL_ALIAS(remove_volatile);
50DECL_ALIAS(remove_pointer);
51DECL_ALIAS(remove_cv);
52DECL_ALIAS(add_pointer);
53DECL_ALIAS(add_const);
54DECL_ALIAS(add_volatile);
55DECL_ALIAS(add_lvalue_reference);
56DECL_ALIAS(add_rvalue_reference);
57#pragma pop_macro("DECL_ALIAS")
58
59template <typename... Ts>
60using common_type_t = type_t<std::common_type<Ts...>>;
61
62// Remove top-level const+volatile+reference qualifiers from the given type.
63template <typename T>
64using remove_cvref_t = remove_cv_t<remove_reference_t<T>>;
65
66// Create a reference-to-const for the given type
67template <typename T>
68using const_reference_t = add_lvalue_reference_t<remove_cvref_t<T> const>;
69
70// A "do-nothing" alias template that always evaluates to void.
71//
72// @tparam Ts Zero or more type arguments, all discarded
73template <typename... Ts>
74using void_t = void;
75
76// Alias for integral_constant<bool, B>.
77template <bool B>
78using bool_constant = std::integral_constant<bool, B>;
79
80// Holds a list of types.
81//
82// This template is never defined, so cannot be used in contexts that require a complete type.
83template <typename...>
84struct mp_list;
85
86// Details for implementing the C++11 detection idiom.
87namespace impl_detection {
88
89// Implementation of detection idiom for is_detected: true case
90template <
91 // A metafunction to try and apply
92 template <class...> class Oper,
93 // The arguments to be given. These are deduced from the mp_list argument
94 typename... Args,
95 // Apply the arguments to the metafunction. If this yields a type, this function
96 // will be viable. If substitution fails, this function is discarded from the
97 // overload set.
98 typename SfinaeHere = Oper<Args...>>
99std::true_type is_detected_f(mp_list<Args...>*);
100
101// Failure case for is_detected. Because this function takes an elipsis, this is
102// less preferred than the above overload that accepts a pointer type directly.
103template <template <class...> class Oper>
104std::false_type is_detected_f(...);
105
106// Provides the detected_or impl
107template <bool IsDetected>
108struct detection;
109
110// Non-detected case:
111template <>
112struct detection<false> {
113 // We just return the default, since the metafunction will not apply
114 template <typename Default, template <class...> class, typename...>
115 using f = Default;
116};
117
118// Detected case:
119template <>
120struct detection<true> {
121 template <typename, template <class...> class Oper, typename... Args>
122 using f = Oper<Args...>;
123};
124
125} // namespace impl_detection
126
127// The type yielded by detected_t if the given type operator does not yield a type.
128struct nonesuch {
129 ~nonesuch() = delete;
130 nonesuch(nonesuch const&) = delete;
131 void operator=(nonesuch const&) = delete;
132};
133
134// Results in true_type if the given metafunction yields a valid type when applied to the given
135// arguments, otherwise yields false_type.
136//
137// @tparam Oper A template that evaluates to a type
138// @tparam Args Some number of arguments to apply to Oper
139template <template <class...> class Oper, typename... Args>
140struct is_detected : decltype(impl_detection::is_detected_f<Oper>(static_cast<mp_list<Args...>*>(nullptr))) {};
141
142// If Oper<Args...> evaluates to a type, yields that type. Otherwise, yields the Dflt type.
143//
144// @tparam Dflt The default type to return if the metafunction does not apply
145// @tparam Oper A metafunction to speculatively apply
146// @tparam Args The arguments to give to the Oper metafunction
147template <typename Dflt, template <class...> class Oper, typename... Args>
148using detected_or =
149 typename impl_detection::detection<is_detected<Oper, Args...>::value>::template f<Dflt, Oper, Args...>;
150
151// If Oper<Args...> evaluates to a type, yields that type. Otherwise, yields the sentinel type
152// `nonesuch`.
153//
154// @tparam Oper A metafunction to try to apply.
155// @tparam Args The metafunction arguments to apply to Oper.
156template <template <class...> class Oper, typename... Args>
157using detected_t = detected_or<nonesuch, Oper, Args...>;
158
159// Impl of conditional_t.
160//
161// Separating the boolean from the type arguments results in significant speedup to compilation due
162// to type memoization.
163template <bool B>
164struct conditional {
165 template <typename IfTrue, typename>
166 using f = IfTrue;
167};
168
169template <>
170struct conditional<false> {
171 template <typename, typename IfFalse>
172 using f = IfFalse;
173};
174
175// Pick one of two types based on a boolean.
176//
177// @tparam B A boolean value
178// @tparam T If `B` is true, pick this type
179// @tparam F If `B` is false, pick this type
180template <bool B, typename T, typename F>
181using conditional_t = typename conditional<B>::template f<T, F>;
182
183// Impl for conjunction+disjunction
184namespace impl_logic {
185
186template <typename FalseType, typename Opers>
187struct conj;
188
189template <typename H, typename... Tail>
190struct conj<bool_constant<H::value || !sizeof...(Tail)>, mp_list<H, Tail...>> : H {};
191
192template <typename F, typename H, typename... Tail>
193struct conj<F, mp_list<H, Tail...>> : conj<F, mp_list<Tail...>> {};
194
195template <typename H>
196struct conj<std::false_type, mp_list<H>> : H {};
197
198template <>
199struct conj<std::false_type, mp_list<>> : std::true_type {};
200
201template <typename TrueType, typename Opers>
202struct disj;
203
204template <typename H, typename... Tail>
205struct disj<bool_constant<H::value && sizeof...(Tail)>, mp_list<H, Tail...>> : H {};
206
207template <typename F, typename H, typename... Tail>
208struct disj<F, mp_list<H, Tail...>> : disj<F, mp_list<Tail...>> {};
209
210template <typename H>
211struct disj<std::true_type, mp_list<H>> : H {};
212
213template <>
214struct disj<std::true_type, mp_list<>> : std::false_type {};
215
216} // namespace impl_logic
217
218// Inherits unambiguously from the first of `Ts...` for which `Ts::value` is a valid expression
219// equal to `false`, or the last of `Ts...` otherwise.
220//
221// conjunction<> (given no arguments) inherits from std::true_type.
222//
223// If any of `Ts::value == false`, then no subsequent `Ts::value` will be instantiated.
224//
225template <typename... Cond>
226struct conjunction : impl_logic::conj<std::false_type, mp_list<Cond...>> {};
227
228// Inherits unambiguous from the first of `Ts...` where `Ts::value` is `true`, or the last of
229// `Ts...` otherwise.
230//
231// Given no arguments, inherits from std::false_type.
232//
233// If any of `Ts::value == true`, then no subsequent `Ts::value` will be instantiated.
234template <typename... Cond>
235struct disjunction : impl_logic::disj<std::true_type, mp_list<Cond...>> {};
236
237// A type trait that produces the negation of the given boolean type trait.
238//
239// @tparam T A type trait with a static member ::value.
240template <typename T>
241struct negation : bool_constant<!T::value> {};
242
243// Yields std::true_type, regardless of type arguments.
244//
245// Useful for wrapping potential decltype() substitution failures in positions
246// that expect a bool_constant type.
247template <typename...>
248using true_t = std::true_type;
249
250namespace impl_requires {
251
252template <typename R>
253R norm_conjunction(R const&);
254
255template <typename R, typename... Cs>
256conjunction<Cs...> norm_conjunction(conjunction<Cs...> const&);
257
258template <typename T>
259using norm_conjunction_t = decltype(norm_conjunction<T>(std::declval<T const&>()));
260
261template <typename Constraint, typename = void>
262struct requirement;
263
264template <typename FailingRequirement>
265struct failed_requirement {
266 failed_requirement(int) = delete;
267
268 template <typename T>
269 static T explain(failed_requirement);
270};
271
272template <typename... SubRequirements>
273struct failed_requirement<conjunction<SubRequirements...>> {
274 failed_requirement(int) = delete;
275
276 template <typename T>
277 static auto explain(int) -> common_type_t<decltype(requirement<SubRequirements>::test::template explain<T>(0))...>;
278};
279
280template <typename Constraint, typename>
281struct requirement {
282 using test = failed_requirement<impl_requires::norm_conjunction_t<Constraint>>;
283};
284
285template <typename Constraint>
286struct requirement<Constraint, enable_if_t<Constraint::value>> {
287 struct test {
288 template <typename T>
289 static T explain(int);
290 };
291};
292
293} // namespace impl_requires
294
295// If none of `Ts::value is 'false'`, yields the type `Type`, otherwise this type is undefined.
296//
297// Use this to perform enable-if style template constraints.
298//
299// @tparam Type The type to return upon success
300// @tparam Traits A list of type traits with nested ::value members
301template <typename Type, typename... Traits>
302#if defined _MSC_VER && _MSC_VER < 1920
303// VS 2017 and older has trouble with expression SFINAE.
304using requires_t = enable_if_t<conjunction<Traits...>::value, Type>;
305#else
306// Generates better error messages in case of substitution failure than a plain enable_if_t:
307using requires_t = decltype(impl_requires::requirement<conjunction<Traits...>>::test::template explain<Type>(0));
308#endif
309
310// If any of `Ts::value` is 'true', this type is undefined, otherwise yields the type `Type`.
311//
312// Use this to perform enable-if template contraints.
313//
314// @tparam Type The type to return upon success
315// @tparam Traits A list of type traits with nested ::value members
316template <typename Type, typename... Traits>
317using requires_not_t = requires_t<Type, negation<disjunction<Traits...>>>;
318
319// Impl: invoke/is_invocable
320namespace impl_invoke {
321
322template <bool IsMemberObject, bool IsMemberFunction>
323struct invoker {
324 template <typename F, typename... Args>
325 constexpr static auto apply(F&& fun, Args&&... args)
326 BSONCXX_PRIVATE_RETURNS(static_cast<F&&>(fun)(static_cast<Args&&>(args)...));
327};
328
329template <>
330struct invoker<false, true> {
331 template <typename F, typename Self, typename... Args>
332 constexpr static auto apply(F&& fun, Self&& self, Args&&... args)
333 BSONCXX_PRIVATE_RETURNS((static_cast<Self&&>(self).*fun)(static_cast<Args&&>(args)...));
334};
335
336template <>
337struct invoker<true, false> {
338 template <typename F, typename Self>
339 constexpr static auto apply(F&& fun, Self&& self) BSONCXX_PRIVATE_RETURNS(static_cast<Self&&>(self).*fun);
340};
341
342} // namespace impl_invoke
343
344static constexpr struct invoke_fn {
345 // Invoke the given object with the given arguments.
346 //
347 // @param fn An invocable: A callable, member object pointer, or member function pointer.
348 // @param args The arguments to use for invocation.
349 // @cond DOXYGEN_DISABLE "Found ';' while parsing initializer list!"
350 template <typename F, typename... Args, typename Fd = remove_cvref_t<F>>
351 constexpr auto operator()(F&& fn, Args&&... args) const
352 BSONCXX_PRIVATE_RETURNS(impl_invoke::invoker<std::is_member_object_pointer<Fd>::value, std::is_member_function_pointer<Fd>::value>::apply(static_cast<F&&>(fn), static_cast<Args&&>(args)...));
353 // @endcond
354} invoke;
355
356// Yields the type that would result from invoking F with the given arguments.
357//
358// @tparam F A invocable: A function pointer or callable object, or a member pointer
359// @tparam Args The arguments to apply
360template <typename F, typename... Args>
361using invoke_result_t = decltype(invoke(std::declval<F>(), std::declval<Args>()...));
362
363// Trait type to detect if the given object can be "invoked" using the given arguments.
364//
365// @tparam F A invocable: A function pointer or callable object, or a member pointer
366// @tparam Args The arguments to match against
367template <typename F, typename... Args>
368struct is_invocable : is_detected<invoke_result_t, F, Args...> {};
369
370// Trait detects whether the given types are the same after the removal of top-level CV-ref
371// qualifiers
372template <typename T, typename U>
373struct is_alike : std::is_same<remove_cvref_t<T>, remove_cvref_t<U>> {};
374
375// Tag type for creating ranked overloads to force disambiguation.
376//
377// @tparam N The ranking of the overload. A higher value is ranked greater than
378// lower values.
379template <std::size_t N>
380struct rank :
381 // @cond DOXYGEN_DISABLE " Detected potential recursive class relation ..."
382 rank<N - 1>
383// @endcond
384{};
385
386template <>
387struct rank<0> {};
388
389namespace swap_detection {
390
391using std::swap;
392
393template <typename T, typename U>
394auto is_swappable_f(rank<0>) -> std::false_type;
395
396template <typename T, typename U>
397auto is_swappable_f(rank<1>) noexcept(
398 noexcept(swap(std::declval<T>(), std::declval<U>())) && noexcept(swap(std::declval<U>(), std::declval<T>())))
399 -> true_t<
400 decltype(swap(std::declval<T>(), std::declval<U>())),
401 decltype(swap(std::declval<U>(), std::declval<T>()))>;
402
403template <typename T, typename U>
404auto is_nothrow_swappable_f(rank<0>) -> std::false_type;
405
406template <typename T, typename U>
407auto is_nothrow_swappable_f(rank<1>) -> bool_constant<
408 noexcept(swap(std::declval<T>(), std::declval<U>())) && noexcept(swap(std::declval<U>(), std::declval<T>()))>;
409
410} // namespace swap_detection
411
412template <typename T, typename U>
413struct is_swappable_with : decltype(swap_detection::is_swappable_f<T, U>(rank<1>{})) {};
414
415template <typename T, typename U>
416struct is_nothrow_swappable_with : decltype(swap_detection::is_nothrow_swappable_f<T, U>(rank<1>{})) {};
417
418template <typename T>
419struct is_swappable : is_swappable_with<T&, T&> {};
420
421template <typename T>
422struct is_nothrow_swappable : is_nothrow_swappable_with<T&, T&> {};
423
424template <typename L, typename R>
425auto is_equality_comparable_f(...) -> std::false_type;
426
427BSONCXX_PRIVATE_WARNINGS_PUSH();
428BSONCXX_PRIVATE_WARNINGS_DISABLE(GNU("-Wfloat-equal"));
429template <typename L, typename R>
430auto is_equality_comparable_f(int, bool b = false)
431 -> true_t<
432 decltype((std::declval<L const&>() == std::declval<R const&>()) ? 0 : 0, (std::declval<R const&>() == std::declval<L const&>()) ? 0 : 0, (std::declval<L const&>() != std::declval<R const&>()) ? 0 : 0, (std::declval<R const&>() != std::declval<L const&>()) ? 0 : 0)>;
433BSONCXX_PRIVATE_WARNINGS_POP();
434
435// Detect whether two types are equality-comparable.
436//
437// Requires L == R, L != R, R == L, and R != L.
438template <typename L, typename R = L>
439struct is_equality_comparable : decltype(is_equality_comparable_f<L, R>(0)) {};
440
441template <typename L, typename R>
442std::false_type is_partially_ordered_with_f(rank<0>);
443
444BSONCXX_PRIVATE_WARNINGS_PUSH();
445BSONCXX_PRIVATE_WARNINGS_DISABLE(Clang("-Wordered-compare-function-pointers"));
446template <typename L, typename R>
447auto is_partially_ordered_with_f(rank<1>) -> true_t<
448 decltype(std::declval<L const&>() > std::declval<R const&>()),
449 decltype(std::declval<L const&>() < std::declval<R const&>()),
450 decltype(std::declval<L const&>() >= std::declval<R const&>()),
451 decltype(std::declval<L const&>() <= std::declval<R const&>()),
452 decltype(std::declval<R const&>() < std::declval<L const&>()),
453 decltype(std::declval<R const&>() > std::declval<L const&>()),
454 decltype(std::declval<R const&>() <= std::declval<L const&>()),
455 decltype(std::declval<R const&>() >= std::declval<L const&>())>;
456BSONCXX_PRIVATE_WARNINGS_POP();
457
458template <typename T, typename U>
459struct is_partially_ordered_with : decltype(is_partially_ordered_with_f<T, U>(rank<1>{})) {};
460
461template <typename T>
462struct is_totally_ordered : conjunction<is_equality_comparable<T>, is_partially_ordered_with<T, T>> {};
463
464template <typename T, typename U>
465struct is_totally_ordered_with : conjunction<
466 is_totally_ordered<T>,
467 is_totally_ordered<U>,
468 is_equality_comparable<T, U>,
469 is_partially_ordered_with<T, U>> {};
470
471} // namespace detail
472} // namespace bsoncxx
473
475
For internal use only!
The bsoncxx v1 macro guard postlude header.
The bsoncxx v1 macro guard prelude header.
bson_value::value value
Equivalent to bsoncxx::v_noabi::types::bson_value::value.
Definition value-fwd.hpp:35
void swap(packed_bit_element< Iterator > a, packed_bit_element< Iterator > b) noexcept
packed_bit_element is Swappable even when it's not an lvalue reference
Definition elements.hpp:172
The top-level namespace within which all bsoncxx library entities are declared.