MongoDB C++ Driver current
Loading...
Searching...
No Matches
type_traits.hpp
1#pragma once
2
3#include <type_traits>
4
5#include <bsoncxx/config/prelude.hpp>
6
7namespace bsoncxx {
8inline namespace v_noabi {
9namespace detail {
10
11#define bsoncxx_ttparam \
12 template <class...> \
13 class
14
16template <typename T>
17using type_t = typename T::type;
18
20template <typename T>
21using value_type_t = typename T::value_type;
22
23template <bool B, typename T = void>
24using enable_if_t = typename std::enable_if<B, T>::type;
25
26#pragma push_macro("DECL_ALIAS")
27#define DECL_ALIAS(Name) \
28 template <typename T> \
29 using Name##_t = type_t<std::Name<T>>
30DECL_ALIAS(decay);
31DECL_ALIAS(make_signed);
32DECL_ALIAS(make_unsigned);
33DECL_ALIAS(remove_reference);
34DECL_ALIAS(remove_const);
35DECL_ALIAS(remove_volatile);
36DECL_ALIAS(remove_cv);
37DECL_ALIAS(add_const);
38DECL_ALIAS(add_volatile);
39DECL_ALIAS(add_lvalue_reference);
40DECL_ALIAS(add_rvalue_reference);
41#pragma pop_macro("DECL_ALIAS")
42
43template <typename... Ts>
44using common_type_t = type_t<std::common_type<Ts...>>;
45
49template <typename T>
50using remove_cvref_t = remove_cv_t<remove_reference_t<T>>;
51
55template <typename T>
56using const_reference_t = add_lvalue_reference_t<const remove_cvref_t<T>>;
57
63template <typename... Ts>
64using void_t = void;
65
69template <bool B>
70using bool_constant = std::integral_constant<bool, B>;
71
77template <typename...>
78struct mp_list;
79
81namespace impl_detection {
82
83// Implementation of detection idiom for is_detected: true case
84template <
85 // A metafunction to try and apply
86 bsoncxx_ttparam Oper,
87 // The arguments to be given. These are deduced from the mp_list argument
88 typename... Args,
89 // Apply the arguments to the metafunction. If this yields a type, this function
90 // will be viable. If substitution fails, this function is discarded from the
91 // overload set.
92 typename SfinaeHere = Oper<Args...>>
93std::true_type is_detected_f(mp_list<Args...>*);
94
95// Failure case for is_detected. Because this function takes an elipsis, this is
96// less preferred than the above overload that accepts a pointer type directly.
97template <bsoncxx_ttparam Oper, typename... Args>
98std::false_type is_detected_f(...);
99
100// Provides the detected_or impl
101template <bool IsDetected>
102struct detection;
103
104// Non-detected case:
105template <>
106struct detection<false> {
107 // We just return the default, since the metafunction will not apply
108 template <typename Default, bsoncxx_ttparam, typename...>
109 using f = Default;
110};
111
112// Detected case:
113template <>
114struct detection<true> {
115 template <typename, bsoncxx_ttparam Oper, typename... Args>
116 using f = Oper<Args...>;
117};
118
119} // namespace impl_detection
120
125struct nonesuch {
126 ~nonesuch() = delete;
127 nonesuch(nonesuch const&) = delete;
128 void operator=(nonesuch const&) = delete;
129};
130
138template <bsoncxx_ttparam Oper, typename... Args>
139struct is_detected
140 : decltype(impl_detection::is_detected_f<Oper>(static_cast<mp_list<Args...>*>(nullptr))) {};
141
150template <typename Dflt, bsoncxx_ttparam Oper, typename... Args>
151using detected_or = typename impl_detection::detection<
152 is_detected<Oper, Args...>::value>::template f<Dflt, Oper, Args...>;
153
161template <bsoncxx_ttparam Oper, typename... Args>
162using detected_t = detected_or<nonesuch, Oper, Args...>;
163
171template <bool B>
172struct conditional {
173 template <typename IfTrue, typename>
174 using f = IfTrue;
175};
176
177template <>
178struct conditional<false> {
179 template <typename, typename IfFalse>
180 using f = IfFalse;
181};
182
190template <bool B, typename T, typename F>
191using conditional_t = typename conditional<B>::template f<T, F>;
192
193// impl for conjunction+disjunction
194namespace impl_logic {
195
196template <typename FalseType, typename Opers>
197struct conj;
198
199template <typename H, typename... Tail>
200struct conj<bool_constant<H::value || !sizeof...(Tail)>, mp_list<H, Tail...>> : H {};
201
202template <typename F, typename H, typename... Tail>
203struct conj<F, mp_list<H, Tail...>> : conj<F, mp_list<Tail...>> {};
204
205template <typename H>
206struct conj<std::false_type, mp_list<H>> : H {};
207
208template <>
209struct conj<std::false_type, mp_list<>> : std::true_type {};
210
211template <typename TrueType, typename Opers>
212struct disj;
213
214template <typename H, typename... Tail>
215struct disj<bool_constant<H::value && sizeof...(Tail)>, mp_list<H, Tail...>> : H {};
216
217template <typename F, typename H, typename... Tail>
218struct disj<F, mp_list<H, Tail...>> : disj<F, mp_list<Tail...>> {};
219
220template <typename H>
221struct disj<std::true_type, mp_list<H>> : H {};
222
223template <>
224struct disj<std::true_type, mp_list<>> : std::false_type {};
225
226} // namespace impl_logic
227
236template <typename... Cond>
237struct conjunction : impl_logic::conj<std::false_type, mp_list<Cond...>> {};
238
247template <typename... Cond>
248struct disjunction : impl_logic::disj<std::true_type, mp_list<Cond...>> {};
249
255template <typename T>
256struct negation : bool_constant<!T::value> {};
257
264template <typename...>
265using true_t = std::true_type;
266
267namespace impl_requires {
268
269template <typename R>
270R norm_conjunction(...);
271
272template <typename R, typename... Cs>
273conjunction<Cs...> norm_conjunction(const conjunction<Cs...>&);
274
275template <typename T>
276using norm_conjunction_t = decltype(norm_conjunction<T>(std::declval<const T&>()));
277
278template <typename Constraint, typename = void>
279struct requirement;
280
281template <typename FailingRequirement>
282struct failed_requirement {
283 failed_requirement(int) = delete;
284
285 template <typename T>
286 static T explain(failed_requirement);
287};
288
289template <typename... SubRequirements>
290struct failed_requirement<conjunction<SubRequirements...>> {
291 failed_requirement(int) = delete;
292
293 template <typename T>
294 static auto explain(int)
295 -> common_type_t<decltype(requirement<SubRequirements>::test::template explain<T>(0))...>;
296};
297
298template <typename Constraint, typename>
299struct requirement {
300 using test = failed_requirement<impl_requires::norm_conjunction_t<Constraint>>;
301};
302
303template <typename Constraint>
304struct requirement<Constraint, enable_if_t<Constraint::value>> {
305 struct test {
306 template <typename T>
307 static T explain(int);
308 };
309};
310
311} // namespace impl_requires
312
322template <typename Type, typename... Traits>
323#if defined _MSC_VER && _MSC_VER < 1920
324// VS 2015 has trouble with expression SFINAE.
325using requires_t = enable_if_t<conjunction<Traits...>::value, Type>;
326#else
327// Generates better error messages in case of substitution failure than a plain enable_if_t:
328using requires_t =
329 decltype(impl_requires::requirement<conjunction<Traits...>>::test::template explain<Type>(0));
330#endif
331
341template <typename Type, typename... Traits>
342using requires_not_t = requires_t<Type, negation<disjunction<Traits...>>>;
343
344// Impl: invoke/is_invocable
345namespace impl_invoke {
346
347#pragma push_macro("RETURNS")
348#define RETURNS(...) \
349 noexcept(noexcept(__VA_ARGS__))->decltype(__VA_ARGS__) { \
350 return __VA_ARGS__; \
351 } \
352 static_assert(true, "")
353
354template <bool IsMemberObject, bool IsMemberFunction>
355struct invoker {
356 template <typename F, typename... Args>
357 constexpr static auto apply(F&& fun, Args&&... args)
358 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 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) RETURNS(static_cast<Self&&>(self).*fun);
372};
373
374} // namespace impl_invoke
375
376static constexpr struct invoke_fn {
384 template <typename F, typename... Args, typename Fd = remove_cvref_t<F>>
385 constexpr auto operator()(F&& fn, Args&&... args) const
386 RETURNS(impl_invoke::invoker<std::is_member_object_pointer<Fd>::value,
387 std::is_member_function_pointer<Fd>::value> //
388 ::apply(static_cast<F&&>(fn), static_cast<Args&&>(args)...));
389} invoke;
390
391#pragma pop_macro("RETURNS")
392
399template <typename F, typename... Args>
400using invoke_result_t = decltype(invoke(std::declval<F>(), std::declval<Args>()...));
401
408template <typename Fun, typename... Args>
409#if defined(_MSC_VER) && _MSC_VER < 1910
410using is_invocable = is_detected<invoke_result_t, Fun, Args...>;
411#else
412struct is_invocable : is_detected<invoke_result_t, Fun, Args...> {
413};
414#endif
415
420template <typename T, typename U>
421struct is_alike : std::is_same<remove_cvref_t<T>, remove_cvref_t<U>> {};
422
423} // namespace detail
424
425} // namespace v_noabi
426
427} // namespace bsoncxx
428
429#include <bsoncxx/config/postlude.hpp>
The top-level namespace for bsoncxx library entities.
Definition element.hpp:24