Fix issue #1237
* Make the conversion operator SFINAE correct. * Workaround a GCC bug with some traits in type_traits.hpp The first bullet-point implies that every `get`/`get_ptr` be SFINAE correct as well.
This commit is contained in:
		
							parent
							
								
									e4bc98d036
								
							
						
					
					
						commit
						4e52277b70
					
				
					 4 changed files with 146 additions and 168 deletions
				
			
		|  | @ -425,6 +425,9 @@ using to_json_function = decltype(T::to_json(std::declval<Args>()...)); | |||
| template <typename T, typename... Args> | ||||
| using from_json_function = decltype(T::from_json(std::declval<Args>()...)); | ||||
| 
 | ||||
| template <typename T, typename U> | ||||
| using get_template_function = decltype(std::declval<T>().template get<U>()); | ||||
| 
 | ||||
| ///////////////////
 | ||||
| // is_ functions //
 | ||||
| ///////////////////
 | ||||
|  | @ -545,8 +548,12 @@ struct is_compatible_integer_type | |||
|       CompatibleNumberIntegerType> {}; | ||||
| 
 | ||||
| // trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
 | ||||
| template<typename BasicJsonType, typename T> | ||||
| struct has_from_json | ||||
| template <typename BasicJsonType, typename T, typename = void> | ||||
| struct has_from_json : std::false_type {}; | ||||
| 
 | ||||
| template <typename BasicJsonType, typename T> | ||||
| struct has_from_json<BasicJsonType, T, | ||||
|            enable_if_t<not is_basic_json<T>::value>> | ||||
| { | ||||
|     using serializer = typename BasicJsonType::template json_serializer<T, void>; | ||||
| 
 | ||||
|  | @ -557,8 +564,11 @@ struct has_from_json | |||
| 
 | ||||
| // This trait checks if JSONSerializer<T>::from_json(json const&) exists
 | ||||
| // this overload is used for non-default-constructible user-defined-types
 | ||||
| template <typename BasicJsonType, typename T, typename = void> | ||||
| struct has_non_default_from_json : std::false_type {}; | ||||
| 
 | ||||
| template<typename BasicJsonType, typename T> | ||||
| struct has_non_default_from_json | ||||
| struct has_non_default_from_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>> | ||||
| { | ||||
|     using serializer = typename BasicJsonType::template json_serializer<T, void>; | ||||
| 
 | ||||
|  | @ -568,8 +578,12 @@ struct has_non_default_from_json | |||
| }; | ||||
| 
 | ||||
| // This trait checks if BasicJsonType::json_serializer<T>::to_json exists
 | ||||
| template<typename BasicJsonType, typename T> | ||||
| struct has_to_json | ||||
| // Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion.
 | ||||
| template <typename BasicJsonType, typename T, typename = void> | ||||
| struct has_to_json : std::false_type {}; | ||||
| 
 | ||||
| template <typename BasicJsonType, typename T> | ||||
| struct has_to_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>> | ||||
| { | ||||
|     using serializer = typename BasicJsonType::template json_serializer<T, void>; | ||||
| 
 | ||||
|  | @ -13696,6 +13710,53 @@ class basic_json | |||
|         return JSONSerializer<ValueTypeCV>::from_json(*this); | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief get a pointer value (implicit) | ||||
| 
 | ||||
|     Implicit pointer access to the internally stored JSON value. No copies are | ||||
|     made. | ||||
| 
 | ||||
|     @warning Writing data to the pointee of the result yields an undefined | ||||
|     state. | ||||
| 
 | ||||
|     @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref | ||||
|     object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, | ||||
|     @ref number_unsigned_t, or @ref number_float_t. Enforced by a static | ||||
|     assertion. | ||||
| 
 | ||||
|     @return pointer to the internally stored JSON value if the requested | ||||
|     pointer type @a PointerType fits to the JSON value; `nullptr` otherwise | ||||
| 
 | ||||
|     @complexity Constant. | ||||
| 
 | ||||
|     @liveexample{The example below shows how pointers to internal values of a | ||||
|     JSON value can be requested. Note that no type conversions are made and a | ||||
|     `nullptr` is returned if the value and the requested pointer type does not | ||||
|     match.,get_ptr} | ||||
| 
 | ||||
|     @since version 1.0.0 | ||||
|     */ | ||||
|     template<typename PointerType, typename std::enable_if< | ||||
|                  std::is_pointer<PointerType>::value, int>::type = 0> | ||||
|     auto get_ptr() noexcept -> decltype(std::declval<basic_json_t&>().get_impl_ptr(std::declval<PointerType>())) | ||||
|     { | ||||
|         // delegate the call to get_impl_ptr<>()
 | ||||
|         return get_impl_ptr(static_cast<PointerType>(nullptr)); | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief get a pointer value (implicit) | ||||
|     @copydoc get_ptr() | ||||
|     */ | ||||
|     template<typename PointerType, typename std::enable_if< | ||||
|                  std::is_pointer<PointerType>::value and | ||||
|                  std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0> | ||||
|     constexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>())) | ||||
|     { | ||||
|         // delegate the call to get_impl_ptr<>() const
 | ||||
|         return get_impl_ptr(static_cast<PointerType>(nullptr)); | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief get a pointer value (explicit) | ||||
| 
 | ||||
|  | @ -13725,7 +13786,7 @@ class basic_json | |||
|     */ | ||||
|     template<typename PointerType, typename std::enable_if< | ||||
|                  std::is_pointer<PointerType>::value, int>::type = 0> | ||||
|     PointerType get() noexcept | ||||
|     auto get() noexcept -> decltype(std::declval<basic_json_t&>().template get_ptr<PointerType>()) | ||||
|     { | ||||
|         // delegate the call to get_ptr
 | ||||
|         return get_ptr<PointerType>(); | ||||
|  | @ -13737,89 +13798,12 @@ class basic_json | |||
|     */ | ||||
|     template<typename PointerType, typename std::enable_if< | ||||
|                  std::is_pointer<PointerType>::value, int>::type = 0> | ||||
|     constexpr const PointerType get() const noexcept | ||||
|     constexpr auto get() const noexcept -> decltype(std::declval<const basic_json_t&>().template get_ptr<PointerType>()) | ||||
|     { | ||||
|         // delegate the call to get_ptr
 | ||||
|         return get_ptr<PointerType>(); | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief get a pointer value (implicit) | ||||
| 
 | ||||
|     Implicit pointer access to the internally stored JSON value. No copies are | ||||
|     made. | ||||
| 
 | ||||
|     @warning Writing data to the pointee of the result yields an undefined | ||||
|     state. | ||||
| 
 | ||||
|     @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref | ||||
|     object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, | ||||
|     @ref number_unsigned_t, or @ref number_float_t. Enforced by a static | ||||
|     assertion. | ||||
| 
 | ||||
|     @return pointer to the internally stored JSON value if the requested | ||||
|     pointer type @a PointerType fits to the JSON value; `nullptr` otherwise | ||||
| 
 | ||||
|     @complexity Constant. | ||||
| 
 | ||||
|     @liveexample{The example below shows how pointers to internal values of a | ||||
|     JSON value can be requested. Note that no type conversions are made and a | ||||
|     `nullptr` is returned if the value and the requested pointer type does not | ||||
|     match.,get_ptr} | ||||
| 
 | ||||
|     @since version 1.0.0 | ||||
|     */ | ||||
|     template<typename PointerType, typename std::enable_if< | ||||
|                  std::is_pointer<PointerType>::value, int>::type = 0> | ||||
|     PointerType get_ptr() noexcept | ||||
|     { | ||||
|         // get the type of the PointerType (remove pointer and const)
 | ||||
|         using pointee_t = typename std::remove_const<typename | ||||
|                           std::remove_pointer<typename | ||||
|                           std::remove_const<PointerType>::type>::type>::type; | ||||
|         // make sure the type matches the allowed types
 | ||||
|         static_assert( | ||||
|             std::is_same<object_t, pointee_t>::value | ||||
|             or std::is_same<array_t, pointee_t>::value | ||||
|             or std::is_same<string_t, pointee_t>::value | ||||
|             or std::is_same<boolean_t, pointee_t>::value | ||||
|             or std::is_same<number_integer_t, pointee_t>::value | ||||
|             or std::is_same<number_unsigned_t, pointee_t>::value | ||||
|             or std::is_same<number_float_t, pointee_t>::value | ||||
|             , "incompatible pointer type"); | ||||
| 
 | ||||
|         // delegate the call to get_impl_ptr<>()
 | ||||
|         return get_impl_ptr(static_cast<PointerType>(nullptr)); | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief get a pointer value (implicit) | ||||
|     @copydoc get_ptr() | ||||
|     */ | ||||
|     template<typename PointerType, typename std::enable_if< | ||||
|                  std::is_pointer<PointerType>::value and | ||||
|                  std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0> | ||||
|     constexpr const PointerType get_ptr() const noexcept | ||||
|     { | ||||
|         // get the type of the PointerType (remove pointer and const)
 | ||||
|         using pointee_t = typename std::remove_const<typename | ||||
|                           std::remove_pointer<typename | ||||
|                           std::remove_const<PointerType>::type>::type>::type; | ||||
|         // make sure the type matches the allowed types
 | ||||
|         static_assert( | ||||
|             std::is_same<object_t, pointee_t>::value | ||||
|             or std::is_same<array_t, pointee_t>::value | ||||
|             or std::is_same<string_t, pointee_t>::value | ||||
|             or std::is_same<boolean_t, pointee_t>::value | ||||
|             or std::is_same<number_integer_t, pointee_t>::value | ||||
|             or std::is_same<number_unsigned_t, pointee_t>::value | ||||
|             or std::is_same<number_float_t, pointee_t>::value | ||||
|             , "incompatible pointer type"); | ||||
| 
 | ||||
|         // delegate the call to get_impl_ptr<>() const
 | ||||
|         return get_impl_ptr(static_cast<PointerType>(nullptr)); | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief get a reference value (implicit) | ||||
| 
 | ||||
|  | @ -13901,12 +13885,14 @@ class basic_json | |||
|                    not std::is_same<ValueType, detail::json_ref<basic_json>>::value and | ||||
|                    not std::is_same<ValueType, typename string_t::value_type>::value and | ||||
|                    not detail::is_basic_json<ValueType>::value | ||||
| 
 | ||||
| #ifndef _MSC_VER  // fix for issue #167 operator<< ambiguity under VS2015
 | ||||
|                    and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value | ||||
| #if defined(JSON_HAS_CPP_17) && defined(_MSC_VER) and _MSC_VER <= 1914 | ||||
|                    and not std::is_same<ValueType, typename std::string_view>::value | ||||
| #endif | ||||
| #endif | ||||
|                    and detail::is_detected<detail::get_template_function, const basic_json_t&, ValueType>::value | ||||
|                    , int >::type = 0 > | ||||
|     operator ValueType() const | ||||
|     { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue