MongoDB C++ Driver mongocxx-4.0.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
17#include <type_traits>
18#include <utility>
19
21
22namespace bsoncxx {
23namespace detail {
24
25// Obtain the nested ::type of the given type argument
26template <typename T>
27using type_t = typename T::type;
28
29// Obtain the value_type member type of the given argument
30template <typename T>
31using value_type_t = typename T::value_type;
32
33template <bool B, typename T = void>
34using enable_if_t = typename std::enable_if<B, T>::type;
35
36#pragma push_macro("DECL_ALIAS")
37#undef DECL_ALIAS
38#define DECL_ALIAS(Name) \
39 template <typename T> \
40 using Name##_t = type_t<std::Name<T>>
41DECL_ALIAS(decay);
42DECL_ALIAS(make_signed);
43DECL_ALIAS(make_unsigned);
44DECL_ALIAS(remove_reference);
45DECL_ALIAS(remove_const);
46DECL_ALIAS(remove_volatile);
47DECL_ALIAS(remove_pointer);
48DECL_ALIAS(remove_cv);
49DECL_ALIAS(add_pointer);
50DECL_ALIAS(add_const);
51DECL_ALIAS(add_volatile);
52DECL_ALIAS(add_lvalue_reference);
53DECL_ALIAS(add_rvalue_reference);
54#pragma pop_macro("DECL_ALIAS")
55
56template <typename... Ts>
57using common_type_t = type_t<std::common_type<Ts...>>;
58
59// Remove top-level const+volatile+reference qualifiers from the given type.
60template <typename T>
61using remove_cvref_t = remove_cv_t<remove_reference_t<T>>;
62
63// Create a reference-to-const for the given type
64template <typename T>
65using const_reference_t = add_lvalue_reference_t<const remove_cvref_t<T>>;
66
67// Workaround for CWG issue 1558.
68template <typename...>
69struct just_void {
70 using type = void;
71};
72
73// A "do-nothing" alias template that always evaluates to void.
74//
75// @tparam Ts Zero or more type arguments, all discarded
76template <typename... Ts>
77using void_t =
78#if defined(_MSC_VER) && _MSC_VER < 1910
79 // Old MSVC requires that the type parameters actually be "used" to trigger SFINAE at caller.
80 // This was resolved by CWG issue 1558.
81 typename just_void<Ts...>::type;
82#else
83 void;
84#endif
85
86// Alias for integral_constant<bool, B>.
87template <bool B>
88using bool_constant = std::integral_constant<bool, B>;
89
90// Holds a list of types.
91//
92// This template is never defined, so cannot be used in contexts that require a complete type.
93template <typename...>
94struct mp_list;
95
96// Details for implementing the C++11 detection idiom.
97namespace impl_detection {
98
99// Implementation of detection idiom for is_detected: true case
100template <
101 // A metafunction to try and apply
102 template <class...>
103 class Oper,
104 // The arguments to be given. These are deduced from the mp_list argument
105 typename... Args,
106 // Apply the arguments to the metafunction. If this yields a type, this function
107 // will be viable. If substitution fails, this function is discarded from the
108 // overload set.
109 typename SfinaeHere = Oper<Args...>>
110std::true_type is_detected_f(mp_list<Args...>*);
111
112// Failure case for is_detected. Because this function takes an elipsis, this is
113// less preferred than the above overload that accepts a pointer type directly.
114template <template <class...> class Oper>
115std::false_type is_detected_f(...);
116
117// Provides the detected_or impl
118template <bool IsDetected>
119struct detection;
120
121// Non-detected case:
122template <>
123struct detection<false> {
124 // We just return the default, since the metafunction will not apply
125 template <typename Default, template <class...> class, typename...>
126 using f = Default;
127};
128
129// Detected case:
130template <>
131struct detection<true> {
132 template <typename, template <class...> class Oper, typename... Args>
133 using f = Oper<Args...>;
134};
135
136// Workaround: MSVC 14.0 forgets whether a type resulting from the evaluation
137// of a template-template parameter to an alias template is a reference.
138template <typename Dflt, typename Void, template <class...> class Oper, typename... Args>
139struct vc140_detection {
140 using type = Dflt;
141};
142
143template <typename Dflt, template <class...> class Oper, typename... Args>
144struct vc140_detection<Dflt, void_t<Oper<Args...>>, Oper, Args...> {
145 using type = Oper<Args...>;
146};
147
148} // namespace impl_detection
149
150// The type yielded by detected_t if the given type operator does not yield a type.
151struct nonesuch {
152 ~nonesuch() = delete;
153 nonesuch(nonesuch const&) = delete;
154 void operator=(nonesuch const&) = delete;
155};
156
157// Results in true_type if the given metafunction yields a valid type when applied to the given
158// arguments, otherwise yields false_type.
159//
160// @tparam Oper A template that evaluates to a type
161// @tparam Args Some number of arguments to apply to Oper
162template <template <class...> class Oper, typename... Args>
163struct is_detected
164 : 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<
177 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(const R&);
284
285template <typename R, typename... Cs>
286conjunction<Cs...> norm_conjunction(const conjunction<Cs...>&);
287
288template <typename T>
289using norm_conjunction_t = decltype(norm_conjunction<T>(std::declval<const T&>()));
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)
308 -> common_type_t<decltype(requirement<SubRequirements>::test::template explain<T>(0))...>;
309};
310
311template <typename Constraint, typename>
312struct requirement {
313 using test = failed_requirement<impl_requires::norm_conjunction_t<Constraint>>;
314};
315
316template <typename Constraint>
317struct requirement<Constraint, enable_if_t<Constraint::value>> {
318 struct test {
319 template <typename T>
320 static T explain(int);
321 };
322};
323
324} // namespace impl_requires
325
326// If none of `Ts::value is 'false'`, yields the type `Type`, otherwise this type is undefined.
327//
328// Use this to perform enable-if style template constraints.
329//
330// @tparam Type The type to return upon success
331// @tparam Traits A list of type traits with nested ::value members
332template <typename Type, typename... Traits>
333#if defined _MSC_VER && _MSC_VER < 1920
334// VS 2015 has trouble with expression SFINAE.
335using requires_t = enable_if_t<conjunction<Traits...>::value, Type>;
336#else
337// Generates better error messages in case of substitution failure than a plain enable_if_t:
338using requires_t =
339 decltype(impl_requires::requirement<conjunction<Traits...>>::test::template explain<Type>(0));
340#endif
341
342// If any of `Ts::value` is 'true', this type is undefined, otherwise yields the type `Type`.
343//
344// Use this to perform enable-if template contraints.
345//
346// @tparam Type The type to return upon success
347// @tparam Traits A list of type traits with nested ::value members
348template <typename Type, typename... Traits>
349using requires_not_t = requires_t<Type, negation<disjunction<Traits...>>>;
350
351// Impl: invoke/is_invocable
352namespace impl_invoke {
353
354template <bool IsMemberObject, bool IsMemberFunction>
355struct invoker {
356 template <typename F, typename... Args>
357 constexpr static auto apply(F&& fun, Args&&... args)
358 BSONCXX_RETURNS(static_cast<F&&>(fun)(static_cast<Args&&>(args)...));
359};
360
361template <>
362struct invoker<false, true> {
363 template <typename F, typename Self, typename... Args>
364 constexpr static auto apply(F&& fun, Self&& self, Args&&... args)
365 BSONCXX_RETURNS((static_cast<Self&&>(self).*fun)(static_cast<Args&&>(args)...));
366};
367
368template <>
369struct invoker<true, false> {
370 template <typename F, typename Self>
371 constexpr static auto apply(F&& fun, Self&& self)
372 BSONCXX_RETURNS(static_cast<Self&&>(self).*fun);
373};
374
375} // namespace impl_invoke
376
377static constexpr struct invoke_fn {
378 // Invoke the given object with the given arguments.
379 //
380 // @param fn An invocable: A callable, member object pointer, or member function pointer.
381 // @param args The arguments to use for invocation.
382 // @cond DOXYGEN_DISABLE "Found ';' while parsing initializer list!"
383 template <typename F, typename... Args, typename Fd = remove_cvref_t<F>>
384 constexpr auto operator()(F&& fn, Args&&... args) const
385 BSONCXX_RETURNS(impl_invoke::invoker<std::is_member_object_pointer<Fd>::value,
386 std::is_member_function_pointer<Fd>::value> //
387 ::apply(static_cast<F&&>(fn), static_cast<Args&&>(args)...));
388 // @endcond
389} invoke;
390
391// Yields the type that would result from invoking F with the given arguments.
392//
393// @tparam F A invocable: A function pointer or callable object, or a member pointer
394// @tparam Args The arguments to apply
395template <typename F, typename... Args>
396using invoke_result_t = decltype(invoke(std::declval<F>(), std::declval<Args>()...));
397
398// Trait type to detect if the given object can be "invoked" using the given arguments.
399//
400// @tparam F A invocable: A function pointer or callable object, or a member pointer
401// @tparam Args The arguments to match against
402template <typename F, typename... Args>
403#if defined(_MSC_VER) && _MSC_VER < 1910
404using is_invocable = is_detected<invoke_result_t, F, Args...>;
405#else
406struct is_invocable : is_detected<invoke_result_t, F, Args...> {
407};
408#endif
409
410// Trait detects whether the given types are the same after the removal of top-level CV-ref
411// qualifiers
412template <typename T, typename U>
413struct is_alike : std::is_same<remove_cvref_t<T>, remove_cvref_t<U>> {};
414
415// Tag type for creating ranked overloads to force disambiguation.
416//
417// @tparam N The ranking of the overload. A higher value is ranked greater than
418// lower values.
419template <std::size_t N>
420struct rank :
421 // @cond DOXYGEN_DISABLE " Detected potential recursive class relation ..."
422 rank<N - 1>
423// @endcond
424{};
425
426template <>
427struct rank<0> {};
428
429namespace swap_detection {
430
431using std::swap;
432
433// Declare an unusable variadic swap. If not present, MSVC 19.00 (VS2015) errors in
434// this header and complains "'std::swap': function does not take 1 arguments" (???).
435void swap(...) = delete;
436
437template <typename T, typename U>
438auto is_swappable_f(rank<0>) -> std::false_type;
439
440template <typename T, typename U>
441auto is_swappable_f(rank<1>) //
442 noexcept(noexcept(swap(std::declval<T>(), std::declval<U>())) //
443 && noexcept(swap(std::declval<U>(), std::declval<T>())))
444 -> true_t<decltype(swap(std::declval<T>(), std::declval<U>())),
445 decltype(swap(std::declval<U>(), std::declval<T>()))>;
446
447template <typename T, typename U>
448auto is_nothrow_swappable_f(rank<0>) -> std::false_type;
449
450template <typename T, typename U>
451auto is_nothrow_swappable_f(rank<1>) //
452 -> bool_constant<noexcept(swap(std::declval<T>(), std::declval<U>())) &&
453 noexcept(swap(std::declval<U>(), std::declval<T>()))>;
454
455} // namespace swap_detection
456
457template <typename T, typename U>
458struct is_swappable_with : decltype(swap_detection::is_swappable_f<T, U>(rank<1>{})) {};
459
460template <typename T, typename U>
461struct is_nothrow_swappable_with
462 : decltype(swap_detection::is_nothrow_swappable_f<T, U>(rank<1>{})) {};
463
464template <typename T>
465struct is_swappable : is_swappable_with<T&, T&> {};
466
467template <typename T>
468struct is_nothrow_swappable : is_nothrow_swappable_with<T&, T&> {};
469
470} // namespace detail
471} // namespace bsoncxx
472
474
The bsoncxx macro guard postlude header.
The bsoncxx 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.
The top-level namespace reserved for the C++ standard library.