Horizon
Loading...
Searching...
No Matches
type_traits.hpp
1#pragma once
2
3#include <limits> // numeric_limits
4#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
5#include <utility> // declval
6#include <tuple> // tuple
7
8#include <nlohmann/detail/macro_scope.hpp>
9
10#include <nlohmann/detail/iterators/iterator_traits.hpp>
11#include <nlohmann/detail/meta/call_std/begin.hpp>
12#include <nlohmann/detail/meta/call_std/end.hpp>
13#include <nlohmann/detail/meta/cpp_future.hpp>
14#include <nlohmann/detail/meta/detected.hpp>
15#include <nlohmann/json_fwd.hpp>
16
17namespace nlohmann
18{
27namespace detail
28{
30// helpers //
32
33// Note to maintainers:
34//
35// Every trait in this file expects a non CV-qualified type.
36// The only exceptions are in the 'aliases for detected' section
37// (i.e. those of the form: decltype(T::member_function(std::declval<T>())))
38//
39// In this case, T has to be properly CV-qualified to constraint the function arguments
40// (e.g. to_json(BasicJsonType&, const T&))
41
42template<typename> struct is_basic_json : std::false_type {};
43
44NLOHMANN_BASIC_JSON_TPL_DECLARATION
45struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {};
46
48// json_ref helpers //
50
51template<typename>
52class json_ref;
53
54template<typename>
55struct is_json_ref : std::false_type {};
56
57template<typename T>
58struct is_json_ref<json_ref<T>> : std::true_type {};
59
61// aliases for detected //
63
64template<typename T>
65using mapped_type_t = typename T::mapped_type;
66
67template<typename T>
68using key_type_t = typename T::key_type;
69
70template<typename T>
71using value_type_t = typename T::value_type;
72
73template<typename T>
74using difference_type_t = typename T::difference_type;
75
76template<typename T>
77using pointer_t = typename T::pointer;
78
79template<typename T>
80using reference_t = typename T::reference;
81
82template<typename T>
83using iterator_category_t = typename T::iterator_category;
84
85template<typename T, typename... Args>
86using to_json_function = decltype(T::to_json(std::declval<Args>()...));
87
88template<typename T, typename... Args>
89using from_json_function = decltype(T::from_json(std::declval<Args>()...));
90
91template<typename T, typename U>
92using get_template_function = decltype(std::declval<T>().template get<U>());
93
94// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
95template<typename BasicJsonType, typename T, typename = void>
96struct has_from_json : std::false_type {};
97
98// trait checking if j.get<T> is valid
99// use this trait instead of std::is_constructible or std::is_convertible,
100// both rely on, or make use of implicit conversions, and thus fail when T
101// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958)
102template <typename BasicJsonType, typename T>
104{
105 static constexpr bool value = is_detected<get_template_function, const BasicJsonType&, T>::value;
106};
107
108template<typename BasicJsonType, typename T>
109struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
110{
111 using serializer = typename BasicJsonType::template json_serializer<T, void>;
112
113 static constexpr bool value =
114 is_detected_exact<void, from_json_function, serializer,
115 const BasicJsonType&, T&>::value;
116};
117
118// This trait checks if JSONSerializer<T>::from_json(json const&) exists
119// this overload is used for non-default-constructible user-defined-types
120template<typename BasicJsonType, typename T, typename = void>
121struct has_non_default_from_json : std::false_type {};
122
123template<typename BasicJsonType, typename T>
124struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
125{
126 using serializer = typename BasicJsonType::template json_serializer<T, void>;
127
128 static constexpr bool value =
129 is_detected_exact<T, from_json_function, serializer,
130 const BasicJsonType&>::value;
131};
132
133// This trait checks if BasicJsonType::json_serializer<T>::to_json exists
134// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion.
135template<typename BasicJsonType, typename T, typename = void>
136struct has_to_json : std::false_type {};
137
138template<typename BasicJsonType, typename T>
139struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
140{
141 using serializer = typename BasicJsonType::template json_serializer<T, void>;
142
143 static constexpr bool value =
144 is_detected_exact<void, to_json_function, serializer, BasicJsonType&,
145 T>::value;
146};
147
148
150// is_ functions //
152
153// https://en.cppreference.com/w/cpp/types/conjunction
154template<class...> struct conjunction : std::true_type { };
155template<class B1> struct conjunction<B1> : B1 { };
156template<class B1, class... Bn>
157struct conjunction<B1, Bn...>
158: std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
159
160// https://en.cppreference.com/w/cpp/types/negation
161template<class B> struct negation : std::integral_constant < bool, !B::value > { };
162
163// Reimplementation of is_constructible and is_default_constructible, due to them being broken for
164// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367).
165// This causes compile errors in e.g. clang 3.5 or gcc 4.9.
166template <typename T>
167struct is_default_constructible : std::is_default_constructible<T> {};
168
169template <typename T1, typename T2>
170struct is_default_constructible<std::pair<T1, T2>>
171 : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {};
172
173template <typename T1, typename T2>
174struct is_default_constructible<const std::pair<T1, T2>>
175 : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {};
176
177template <typename... Ts>
178struct is_default_constructible<std::tuple<Ts...>>
179 : conjunction<is_default_constructible<Ts>...> {};
180
181template <typename... Ts>
182struct is_default_constructible<const std::tuple<Ts...>>
183 : conjunction<is_default_constructible<Ts>...> {};
184
185
186template <typename T, typename... Args>
187struct is_constructible : std::is_constructible<T, Args...> {};
188
189template <typename T1, typename T2>
190struct is_constructible<std::pair<T1, T2>> : is_default_constructible<std::pair<T1, T2>> {};
191
192template <typename T1, typename T2>
193struct is_constructible<const std::pair<T1, T2>> : is_default_constructible<const std::pair<T1, T2>> {};
194
195template <typename... Ts>
196struct is_constructible<std::tuple<Ts...>> : is_default_constructible<std::tuple<Ts...>> {};
197
198template <typename... Ts>
199struct is_constructible<const std::tuple<Ts...>> : is_default_constructible<const std::tuple<Ts...>> {};
200
201
202template<typename T, typename = void>
203struct is_iterator_traits : std::false_type {};
204
205template<typename T>
207{
208 private:
210
211 public:
212 static constexpr auto value =
213 is_detected<value_type_t, traits>::value &&
214 is_detected<difference_type_t, traits>::value &&
215 is_detected<pointer_t, traits>::value &&
216 is_detected<iterator_category_t, traits>::value &&
217 is_detected<reference_t, traits>::value;
218};
219
220template<typename T>
222{
223 private:
224 using t_ref = typename std::add_lvalue_reference<T>::type;
225
226 using iterator = detected_t<result_of_begin, t_ref>;
227 using sentinel = detected_t<result_of_end, t_ref>;
228
229 // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator
230 // and https://en.cppreference.com/w/cpp/iterator/sentinel_for
231 // but reimplementing these would be too much work, as a lot of other concepts are used underneath
232 static constexpr auto is_iterator_begin =
234
235 public:
236 static constexpr bool value = !std::is_same<iterator, nonesuch>::value && !std::is_same<sentinel, nonesuch>::value && is_iterator_begin;
237};
238
239template<typename R>
240using iterator_t = enable_if_t<is_range<R>::value, result_of_begin<decltype(std::declval<R&>())>>;
241
242template<typename T>
243using range_value_t = value_type_t<iterator_traits<iterator_t<T>>>;
244
245// The following implementation of is_complete_type is taken from
246// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/
247// and is written by Xiang Fan who agreed to using it in this library.
248
249template<typename T, typename = void>
250struct is_complete_type : std::false_type {};
251
252template<typename T>
253struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
254
255template<typename BasicJsonType, typename CompatibleObjectType,
256 typename = void>
257struct is_compatible_object_type_impl : std::false_type {};
258
259template<typename BasicJsonType, typename CompatibleObjectType>
261 BasicJsonType, CompatibleObjectType,
262 enable_if_t < is_detected<mapped_type_t, CompatibleObjectType>::value&&
263 is_detected<key_type_t, CompatibleObjectType>::value >>
264{
265 using object_t = typename BasicJsonType::object_t;
266
267 // macOS's is_constructible does not play well with nonesuch...
268 static constexpr bool value =
269 is_constructible<typename object_t::key_type,
270 typename CompatibleObjectType::key_type>::value &&
271 is_constructible<typename object_t::mapped_type,
272 typename CompatibleObjectType::mapped_type>::value;
273};
274
275template<typename BasicJsonType, typename CompatibleObjectType>
277 : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};
278
279template<typename BasicJsonType, typename ConstructibleObjectType,
280 typename = void>
281struct is_constructible_object_type_impl : std::false_type {};
282
283template<typename BasicJsonType, typename ConstructibleObjectType>
285 BasicJsonType, ConstructibleObjectType,
286 enable_if_t < is_detected<mapped_type_t, ConstructibleObjectType>::value&&
287 is_detected<key_type_t, ConstructibleObjectType>::value >>
288{
289 using object_t = typename BasicJsonType::object_t;
290
291 static constexpr bool value =
293 (std::is_move_assignable<ConstructibleObjectType>::value ||
294 std::is_copy_assignable<ConstructibleObjectType>::value) &&
295 (is_constructible<typename ConstructibleObjectType::key_type,
296 typename object_t::key_type>::value &&
297 std::is_same <
298 typename object_t::mapped_type,
299 typename ConstructibleObjectType::mapped_type >::value)) ||
300 (has_from_json<BasicJsonType,
301 typename ConstructibleObjectType::mapped_type>::value ||
303 BasicJsonType,
304 typename ConstructibleObjectType::mapped_type >::value);
305};
306
307template<typename BasicJsonType, typename ConstructibleObjectType>
309 : is_constructible_object_type_impl<BasicJsonType,
310 ConstructibleObjectType> {};
311
312template<typename BasicJsonType, typename CompatibleStringType,
313 typename = void>
314struct is_compatible_string_type_impl : std::false_type {};
315
316template<typename BasicJsonType, typename CompatibleStringType>
318 BasicJsonType, CompatibleStringType,
319 enable_if_t<is_detected_convertible<typename BasicJsonType::string_t::value_type,
320 range_value_t,
321 CompatibleStringType>::value >>
322{
323 static constexpr auto value =
325};
326
327template<typename BasicJsonType, typename ConstructibleStringType>
329 : is_compatible_string_type_impl<BasicJsonType, ConstructibleStringType> {};
330
331template<typename BasicJsonType, typename ConstructibleStringType,
332 typename = void>
333struct is_constructible_string_type_impl : std::false_type {};
334
335template<typename BasicJsonType, typename ConstructibleStringType>
337 BasicJsonType, ConstructibleStringType,
338 enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type,
339 value_type_t, ConstructibleStringType>::value >>
340{
341 static constexpr auto value =
342 is_constructible<ConstructibleStringType,
343 typename BasicJsonType::string_t>::value;
344};
345
346template<typename BasicJsonType, typename ConstructibleStringType>
348 : is_constructible_string_type_impl<BasicJsonType, ConstructibleStringType> {};
349
350template<typename BasicJsonType, typename CompatibleArrayType, typename = void>
351struct is_compatible_array_type_impl : std::false_type {};
352
353template<typename BasicJsonType, typename CompatibleArrayType>
355 BasicJsonType, CompatibleArrayType,
356 enable_if_t <
357 is_detected<iterator_t, CompatibleArrayType>::value&&
358 is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value >>
359{
360 static constexpr bool value =
361 is_constructible<BasicJsonType,
362 range_value_t<CompatibleArrayType>>::value;
363};
364
365template<typename BasicJsonType, typename CompatibleArrayType>
367 : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};
368
369template<typename BasicJsonType, typename ConstructibleArrayType, typename = void>
370struct is_constructible_array_type_impl : std::false_type {};
371
372template<typename BasicJsonType, typename ConstructibleArrayType>
374 BasicJsonType, ConstructibleArrayType,
375 enable_if_t<std::is_same<ConstructibleArrayType,
376 typename BasicJsonType::value_type>::value >>
377 : std::true_type {};
378
379template<typename BasicJsonType, typename ConstructibleArrayType>
381 BasicJsonType, ConstructibleArrayType,
382 enable_if_t < !std::is_same<ConstructibleArrayType,
383 typename BasicJsonType::value_type>::value&&
384 !is_compatible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
385 is_default_constructible<ConstructibleArrayType>::value&&
386(std::is_move_assignable<ConstructibleArrayType>::value ||
387 std::is_copy_assignable<ConstructibleArrayType>::value)&&
388is_detected<iterator_t, ConstructibleArrayType>::value&&
389is_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value&&
390is_detected<range_value_t, ConstructibleArrayType>::value&&
392detected_t<range_value_t, ConstructibleArrayType >>::value >>
393{
394 using value_type = range_value_t<ConstructibleArrayType>;
395
396 static constexpr bool value =
397 std::is_same<value_type,
398 typename BasicJsonType::array_t::value_type>::value ||
399 has_from_json<BasicJsonType,
400 value_type>::value ||
402 BasicJsonType,
403 value_type >::value;
404};
405
406template<typename BasicJsonType, typename ConstructibleArrayType>
408 : is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {};
409
410template<typename RealIntegerType, typename CompatibleNumberIntegerType,
411 typename = void>
412struct is_compatible_integer_type_impl : std::false_type {};
413
414template<typename RealIntegerType, typename CompatibleNumberIntegerType>
416 RealIntegerType, CompatibleNumberIntegerType,
417 enable_if_t < std::is_integral<RealIntegerType>::value&&
418 std::is_integral<CompatibleNumberIntegerType>::value&&
419 !std::is_same<bool, CompatibleNumberIntegerType>::value >>
420{
421 // is there an assert somewhere on overflows?
422 using RealLimits = std::numeric_limits<RealIntegerType>;
423 using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
424
425 static constexpr auto value =
426 is_constructible<RealIntegerType,
427 CompatibleNumberIntegerType>::value &&
428 CompatibleLimits::is_integer &&
429 RealLimits::is_signed == CompatibleLimits::is_signed;
430};
431
432template<typename RealIntegerType, typename CompatibleNumberIntegerType>
434 : is_compatible_integer_type_impl<RealIntegerType,
435 CompatibleNumberIntegerType> {};
436
437template<typename BasicJsonType, typename CompatibleType, typename = void>
438struct is_compatible_type_impl: std::false_type {};
439
440template<typename BasicJsonType, typename CompatibleType>
442 BasicJsonType, CompatibleType,
443 enable_if_t<is_complete_type<CompatibleType>::value >>
444{
445 static constexpr bool value =
447};
448
449template<typename BasicJsonType, typename CompatibleType>
451 : is_compatible_type_impl<BasicJsonType, CompatibleType> {};
452
453template<typename T1, typename T2>
454struct is_constructible_tuple : std::false_type {};
455
456template<typename T1, typename... Args>
457struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<is_constructible<T1, Args>...> {};
458
459// a naive helper to check if a type is an ordered_map (exploits the fact that
460// ordered_map inherits capacity() from std::vector)
461template <typename T>
463{
464 using one = char;
465
466 struct two
467 {
468 char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
469 };
470
471 template <typename C> static one test( decltype(&C::capacity) ) ;
472 template <typename C> static two test(...);
473
474 enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
475};
476
477// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324)
478template < typename T, typename U, enable_if_t < !std::is_same<T, U>::value, int > = 0 >
479T conditional_static_cast(U value)
480{
481 return static_cast<T>(value);
482}
483
484template<typename T, typename U, enable_if_t<std::is_same<T, U>::value, int> = 0>
485T conditional_static_cast(U value)
486{
487 return value;
488}
489
490} // namespace detail
491} // namespace nlohmann
Definition json_ref.hpp:14
@ value
the parser finished reading a JSON value
namespace for Niels Lohmann
Definition adl_serializer.hpp:12
Definition type_traits.hpp:154
Definition type_traits.hpp:96
Definition type_traits.hpp:121
Definition type_traits.hpp:136
Definition type_traits.hpp:42
Definition type_traits.hpp:367
Definition type_traits.hpp:435
Definition type_traits.hpp:277
Definition type_traits.hpp:329
Definition type_traits.hpp:438
Definition type_traits.hpp:451
Definition type_traits.hpp:250
Definition type_traits.hpp:408
Definition type_traits.hpp:454
Definition type_traits.hpp:187
Definition type_traits.hpp:167
Definition type_traits.hpp:104
Definition type_traits.hpp:203
Definition type_traits.hpp:55
Definition type_traits.hpp:467
Definition type_traits.hpp:463
Definition type_traits.hpp:222
Definition iterator_traits.hpp:32
Definition type_traits.hpp:161