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