MongoDB C++ Driver 4.2.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// Workaround for CWG issue 1558.
71template <typename...>
72struct just_void {
73 using type = void;
74};
75
76// A "do-nothing" alias template that always evaluates to void.
77//
78// @tparam Ts Zero or more type arguments, all discarded
79template <typename... Ts>
80using void_t =
81#if defined(_MSC_VER) && _MSC_VER < 1910
82 // Old MSVC requires that the type parameters actually be "used" to trigger SFINAE at caller.
83 // This was resolved by CWG issue 1558.
84 typename just_void<Ts...>::type;
85#else
86 void;
87#endif
88
89// Alias for integral_constant<bool, B>.
90template <bool B>
91using bool_constant = std::integral_constant<bool, B>;
92
93// Holds a list of types.
94//
95// This template is never defined, so cannot be used in contexts that require a complete type.
96template <typename...>
97struct mp_list;
98
99// Details for implementing the C++11 detection idiom.
100namespace impl_detection {
101
102// Implementation of detection idiom for is_detected: true case
103template <
104 // A metafunction to try and apply
105 template <class...> class Oper,
106 // The arguments to be given. These are deduced from the mp_list argument
107 typename... Args,
108 // Apply the arguments to the metafunction. If this yields a type, this function
109 // will be viable. If substitution fails, this function is discarded from the
110 // overload set.
111 typename SfinaeHere = Oper<Args...>>
112std::true_type is_detected_f(mp_list<Args...>*);
113
114// Failure case for is_detected. Because this function takes an elipsis, this is
115// less preferred than the above overload that accepts a pointer type directly.
116template <template <class...> class Oper>
117std::false_type is_detected_f(...);
118
119// Provides the detected_or impl
120template <bool IsDetected>
121struct detection;
122
123// Non-detected case:
124template <>
125struct detection<false> {
126 // We just return the default, since the metafunction will not apply
127 template <typename Default, template <class...> class, typename...>
128 using f = Default;
129};
130
131// Detected case:
132template <>
133struct detection<true> {
134 template <typename, template <class...> class Oper, typename... Args>
135 using f = Oper<Args...>;
136};
137
138// Workaround: MSVC 14.0 forgets whether a type resulting from the evaluation
139// of a template-template parameter to an alias template is a reference.
140template <typename Dflt, typename Void, template <class...> class Oper, typename... Args>
141struct vc140_detection {
142 using type = Dflt;
143};
144
145template <typename Dflt, template <class...> class Oper, typename... Args>
146struct vc140_detection<Dflt, void_t<Oper<Args...>>, Oper, Args...> {
147 using type = Oper<Args...>;
148};
149
150} // namespace impl_detection
151
152// The type yielded by detected_t if the given type operator does not yield a type.
153struct nonesuch {
154 ~nonesuch() = delete;
155 nonesuch(nonesuch const&) = delete;
156 void operator=(nonesuch const&) = delete;
157};
158
159// Results in true_type if the given metafunction yields a valid type when applied to the given
160// arguments, otherwise yields false_type.
161//
162// @tparam Oper A template that evaluates to a type
163// @tparam Args Some number of arguments to apply to Oper
164template <template <class...> class Oper, typename... Args>
165struct is_detected : decltype(impl_detection::is_detected_f<Oper>(static_cast<mp_list<Args...>*>(nullptr))) {};
166
167// If Oper<Args...> evaluates to a type, yields that type. Otherwise, yields the Dflt type.
168//
169// @tparam Dflt The default type to return if the metafunction does not apply
170// @tparam Oper A metafunction to speculatively apply
171// @tparam Args The arguments to give to the Oper metafunction
172template <typename Dflt, template <class...> class Oper, typename... Args>
173using detected_or =
174#if defined(_MSC_VER) && _MSC_VER < 1910
175 typename impl_detection::vc140_detection<Dflt, void, Oper, Args...>::type
176#else
177 typename impl_detection::detection<is_detected<Oper, Args...>::value>::template f<Dflt, Oper, Args...>
178#endif
179 ;
180
181// If Oper<Args...> evaluates to a type, yields that type. Otherwise, yields the sentinel type
182// `nonesuch`.
183//
184// @tparam Oper A metafunction to try to apply.
185// @tparam Args The metafunction arguments to apply to Oper.
186template <template <class...> class Oper, typename... Args>
187using detected_t = detected_or<nonesuch, Oper, Args...>;
188
189// Impl of conditional_t.
190//
191// Separating the boolean from the type arguments results in significant speedup to compilation due
192// to type memoization.
193template <bool B>
194struct conditional {
195 template <typename IfTrue, typename>
196 using f = IfTrue;
197};
198
199template <>
200struct conditional<false> {
201 template <typename, typename IfFalse>
202 using f = IfFalse;
203};
204
205// Pick one of two types based on a boolean.
206//
207// @tparam B A boolean value
208// @tparam T If `B` is true, pick this type
209// @tparam F If `B` is false, pick this type
210template <bool B, typename T, typename F>
211using conditional_t = typename conditional<B>::template f<T, F>;
212
213// Impl for conjunction+disjunction
214namespace impl_logic {
215
216template <typename FalseType, typename Opers>
217struct conj;
218
219template <typename H, typename... Tail>
220struct conj<bool_constant<H::value || !sizeof...(Tail)>, mp_list<H, Tail...>> : H {};
221
222template <typename F, typename H, typename... Tail>
223struct conj<F, mp_list<H, Tail...>> : conj<F, mp_list<Tail...>> {};
224
225template <typename H>
226struct conj<std::false_type, mp_list<H>> : H {};
227
228template <>
229struct conj<std::false_type, mp_list<>> : std::true_type {};
230
231template <typename TrueType, typename Opers>
232struct disj;
233
234template <typename H, typename... Tail>
235struct disj<bool_constant<H::value && sizeof...(Tail)>, mp_list<H, Tail...>> : H {};
236
237template <typename F, typename H, typename... Tail>
238struct disj<F, mp_list<H, Tail...>> : disj<F, mp_list<Tail...>> {};
239
240template <typename H>
241struct disj<std::true_type, mp_list<H>> : H {};
242
243template <>
244struct disj<std::true_type, mp_list<>> : std::false_type {};
245
246} // namespace impl_logic
247
248// Inherits unambiguously from the first of `Ts...` for which `Ts::value` is a valid expression
249// equal to `false`, or the last of `Ts...` otherwise.
250//
251// conjunction<> (given no arguments) inherits from std::true_type.
252//
253// If any of `Ts::value == false`, then no subsequent `Ts::value` will be instantiated.
254//
255template <typename... Cond>
256struct conjunction : impl_logic::conj<std::false_type, mp_list<Cond...>> {};
257
258// Inherits unambiguous from the first of `Ts...` where `Ts::value` is `true`, or the last of
259// `Ts...` otherwise.
260//
261// Given no arguments, inherits from std::false_type.
262//
263// If any of `Ts::value == true`, then no subsequent `Ts::value` will be instantiated.
264template <typename... Cond>
265struct disjunction : impl_logic::disj<std::true_type, mp_list<Cond...>> {};
266
267// A type trait that produces the negation of the given boolean type trait.
268//
269// @tparam T A type trait with a static member ::value.
270template <typename T>
271struct negation : bool_constant<!T::value> {};
272
273// Yields std::true_type, regardless of type arguments.
274//
275// Useful for wrapping potential decltype() substitution failures in positions
276// that expect a bool_constant type.
277template <typename...>
278using true_t = std::true_type;
279
280namespace impl_requires {
281
282template <typename R>
283R norm_conjunction(R const&);
284
285template <typename R, typename... Cs>
286conjunction<Cs...> norm_conjunction(conjunction<Cs...> const&);
287
288template <typename T>
289using norm_conjunction_t = decltype(norm_conjunction<T>(std::declval<T const&>()));
290
291template <typename Constraint, typename = void>
292struct requirement;
293
294template <typename FailingRequirement>
295struct failed_requirement {
296 failed_requirement(int) = delete;
297
298 template <typename T>
299 static T explain(failed_requirement);
300};
301
302template <typename... SubRequirements>
303struct failed_requirement<conjunction<SubRequirements...>> {
304 failed_requirement(int) = delete;
305
306 template <typename T>
307 static auto explain(int) -> common_type_t<decltype(requirement<SubRequirements>::test::template explain<T>(0))...>;
308};
309
310template <typename Constraint, typename>
311struct requirement {
312 using test = failed_requirement<impl_requires::norm_conjunction_t<Constraint>>;
313};
314
315template <typename Constraint>
316struct requirement<Constraint, enable_if_t<Constraint::value>> {
317 struct test {
318 template <typename T>
319 static T explain(int);
320 };
321};
322
323} // namespace impl_requires
324
325// If none of `Ts::value is 'false'`, yields the type `Type`, otherwise this type is undefined.
326//
327// Use this to perform enable-if style template constraints.
328//
329// @tparam Type The type to return upon success
330// @tparam Traits A list of type traits with nested ::value members
331template <typename Type, typename... Traits>
332#if defined _MSC_VER && _MSC_VER < 1920
333// VS 2015 has trouble with expression SFINAE.
334using requires_t = enable_if_t<conjunction<Traits...>::value, Type>;
335#else
336// Generates better error messages in case of substitution failure than a plain enable_if_t:
337using requires_t = decltype(impl_requires::requirement<conjunction<Traits...>>::test::template explain<Type>(0));
338#endif
339
340// If any of `Ts::value` is 'true', this type is undefined, otherwise yields the type `Type`.
341//
342// Use this to perform enable-if template contraints.
343//
344// @tparam Type The type to return upon success
345// @tparam Traits A list of type traits with nested ::value members
346template <typename Type, typename... Traits>
347using requires_not_t = requires_t<Type, negation<disjunction<Traits...>>>;
348
349// Impl: invoke/is_invocable
350namespace impl_invoke {
351
352template <bool IsMemberObject, bool IsMemberFunction>
353struct invoker {
354 template <typename F, typename... Args>
355 constexpr static auto apply(F&& fun, Args&&... args)
356 BSONCXX_PRIVATE_RETURNS(static_cast<F&&>(fun)(static_cast<Args&&>(args)...));
357};
358
359template <>
360struct invoker<false, true> {
361 template <typename F, typename Self, typename... Args>
362 constexpr static auto apply(F&& fun, Self&& self, Args&&... args)
363 BSONCXX_PRIVATE_RETURNS((static_cast<Self&&>(self).*fun)(static_cast<Args&&>(args)...));
364};
365
366template <>
367struct invoker<true, false> {
368 template <typename F, typename Self>
369 constexpr static auto apply(F&& fun, Self&& self) BSONCXX_PRIVATE_RETURNS(static_cast<Self&&>(self).*fun);
370};
371
372} // namespace impl_invoke
373
374static constexpr struct invoke_fn {
375 // Invoke the given object with the given arguments.
376 //
377 // @param fn An invocable: A callable, member object pointer, or member function pointer.
378 // @param args The arguments to use for invocation.
379 // @cond DOXYGEN_DISABLE "Found ';' while parsing initializer list!"
380 template <typename F, typename... Args, typename Fd = remove_cvref_t<F>>
381 constexpr auto operator()(F&& fn, Args&&... args) const
382 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)...));
383 // @endcond
384} invoke;
385
386// Yields the type that would result from invoking F with the given arguments.
387//
388// @tparam F A invocable: A function pointer or callable object, or a member pointer
389// @tparam Args The arguments to apply
390template <typename F, typename... Args>
391using invoke_result_t = decltype(invoke(std::declval<F>(), std::declval<Args>()...));
392
393// Trait type to detect if the given object can be "invoked" using the given arguments.
394//
395// @tparam F A invocable: A function pointer or callable object, or a member pointer
396// @tparam Args The arguments to match against
397template <typename F, typename... Args>
398#if defined(_MSC_VER) && _MSC_VER < 1910
399using is_invocable = is_detected<invoke_result_t, F, Args...>;
400#else
401struct is_invocable : is_detected<invoke_result_t, F, Args...> {
402};
403#endif
404
405// Trait detects whether the given types are the same after the removal of top-level CV-ref
406// qualifiers
407template <typename T, typename U>
408struct is_alike : std::is_same<remove_cvref_t<T>, remove_cvref_t<U>> {};
409
410// Tag type for creating ranked overloads to force disambiguation.
411//
412// @tparam N The ranking of the overload. A higher value is ranked greater than
413// lower values.
414template <std::size_t N>
415struct rank :
416 // @cond DOXYGEN_DISABLE " Detected potential recursive class relation ..."
417 rank<N - 1>
418// @endcond
419{};
420
421template <>
422struct rank<0> {};
423
424namespace swap_detection {
425
426using std::swap;
427
428// Declare an unusable variadic swap. If not present, MSVC 19.00 (VS2015) errors in
429// this header and complains "'std::swap': function does not take 1 arguments" (???).
430void swap(...) = delete;
431
432template <typename T, typename U>
433auto is_swappable_f(rank<0>) -> std::false_type;
434
435template <typename T, typename U>
436auto is_swappable_f(rank<1>) noexcept(
437 noexcept(swap(std::declval<T>(), std::declval<U>())) && noexcept(swap(std::declval<U>(), std::declval<T>())))
438 -> true_t<
439 decltype(swap(std::declval<T>(), std::declval<U>())),
440 decltype(swap(std::declval<U>(), std::declval<T>()))>;
441
442template <typename T, typename U>
443auto is_nothrow_swappable_f(rank<0>) -> std::false_type;
444
445template <typename T, typename U>
446auto is_nothrow_swappable_f(rank<1>) -> bool_constant<
447 noexcept(swap(std::declval<T>(), std::declval<U>())) && noexcept(swap(std::declval<U>(), std::declval<T>()))>;
448
449} // namespace swap_detection
450
451template <typename T, typename U>
452struct is_swappable_with : decltype(swap_detection::is_swappable_f<T, U>(rank<1>{})) {};
453
454template <typename T, typename U>
455struct is_nothrow_swappable_with : decltype(swap_detection::is_nothrow_swappable_f<T, U>(rank<1>{})) {};
456
457template <typename T>
458struct is_swappable : is_swappable_with<T&, T&> {};
459
460template <typename T>
461struct is_nothrow_swappable : is_nothrow_swappable_with<T&, T&> {};
462
463template <typename L, typename R>
464auto is_equality_comparable_f(...) -> std::false_type;
465
466BSONCXX_PRIVATE_WARNINGS_PUSH();
467BSONCXX_PRIVATE_WARNINGS_DISABLE(GNU("-Wfloat-equal"));
468template <typename L, typename R>
469auto is_equality_comparable_f(int, bool b = false)
470 -> true_t<
471 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)>;
472BSONCXX_PRIVATE_WARNINGS_POP();
473
474// Detect whether two types are equality-comparable.
475//
476// Requires L == R, L != R, R == L, and R != L.
477template <typename L, typename R = L>
478struct is_equality_comparable : decltype(is_equality_comparable_f<L, R>(0)) {};
479
480template <typename L, typename R>
481std::false_type is_partially_ordered_with_f(rank<0>);
482
483BSONCXX_PRIVATE_WARNINGS_PUSH();
484BSONCXX_PRIVATE_WARNINGS_DISABLE(Clang("-Wordered-compare-function-pointers"));
485template <typename L, typename R>
486auto is_partially_ordered_with_f(rank<1>) -> true_t<
487 decltype(std::declval<L const&>() > std::declval<R const&>()),
488 decltype(std::declval<L const&>() < std::declval<R const&>()),
489 decltype(std::declval<L const&>() >= std::declval<R const&>()),
490 decltype(std::declval<L const&>() <= std::declval<R const&>()),
491 decltype(std::declval<R const&>() < std::declval<L const&>()),
492 decltype(std::declval<R const&>() > std::declval<L const&>()),
493 decltype(std::declval<R const&>() <= std::declval<L const&>()),
494 decltype(std::declval<R const&>() >= std::declval<L const&>())>;
495BSONCXX_PRIVATE_WARNINGS_POP();
496
497template <typename T, typename U>
498struct is_partially_ordered_with : decltype(is_partially_ordered_with_f<T, U>(rank<1>{})) {};
499
500template <typename T>
501struct is_totally_ordered : conjunction<is_equality_comparable<T>, is_partially_ordered_with<T, T>> {};
502
503template <typename T, typename U>
504struct is_totally_ordered_with : conjunction<
505 is_totally_ordered<T>,
506 is_totally_ordered<U>,
507 is_equality_comparable<T, U>,
508 is_partially_ordered_with<T, U>> {};
509
510} // namespace detail
511} // namespace bsoncxx
512
514
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
type
An enumeration of each BSON type.
Definition types.hpp:47
The top-level namespace within which all bsoncxx library entities are declared.