fix sfinae on basic_json UDT constructor
Avoid compiler errors when performing SFINAE checks on basic_json and incomplete types.
This commit is contained in:
		
							parent
							
								
									3ac674562f
								
							
						
					
					
						commit
						dcee778c1e
					
				
					 4 changed files with 83 additions and 20 deletions
				
			
		| 
						 | 
				
			
			@ -96,6 +96,14 @@ template<> struct priority_tag<0> {};
 | 
			
		|||
// has_/is_ functions //
 | 
			
		||||
////////////////////////
 | 
			
		||||
 | 
			
		||||
// source: https://stackoverflow.com/a/37193089/4116453
 | 
			
		||||
 | 
			
		||||
template <typename T, typename = void>
 | 
			
		||||
struct is_complete_type : std::false_type {};
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
 | 
			
		||||
 | 
			
		||||
NLOHMANN_JSON_HAS_HELPER(mapped_type);
 | 
			
		||||
NLOHMANN_JSON_HAS_HELPER(key_type);
 | 
			
		||||
NLOHMANN_JSON_HAS_HELPER(value_type);
 | 
			
		||||
| 
						 | 
				
			
			@ -171,7 +179,6 @@ struct is_compatible_integer_type
 | 
			
		|||
        RealIntegerType, CompatibleNumberIntegerType > ::value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
 | 
			
		||||
template<typename BasicJsonType, typename T>
 | 
			
		||||
struct has_from_json
 | 
			
		||||
| 
						 | 
				
			
			@ -221,6 +228,23 @@ struct has_to_json
 | 
			
		|||
                                      std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename BasicJsonType, typename CompatibleCompleteType>
 | 
			
		||||
struct is_compatible_complete_type
 | 
			
		||||
{
 | 
			
		||||
    static constexpr bool value =
 | 
			
		||||
        not std::is_base_of<std::istream, CompatibleCompleteType>::value and
 | 
			
		||||
        not std::is_same<BasicJsonType, CompatibleCompleteType>::value and
 | 
			
		||||
        not is_basic_json_nested_type<BasicJsonType, CompatibleCompleteType>::value and
 | 
			
		||||
        has_to_json<BasicJsonType, CompatibleCompleteType>::value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename BasicJsonType, typename CompatibleType>
 | 
			
		||||
struct is_compatible_type
 | 
			
		||||
    : conjunction<is_complete_type<CompatibleType>,
 | 
			
		||||
      is_compatible_complete_type<BasicJsonType, CompatibleType>>
 | 
			
		||||
{
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// taken from ranges-v3
 | 
			
		||||
template<typename T>
 | 
			
		||||
struct static_const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1551,15 +1551,13 @@ class basic_json
 | 
			
		|||
 | 
			
		||||
    @since version 2.1.0
 | 
			
		||||
    */
 | 
			
		||||
    template<typename CompatibleType, typename U = detail::uncvref_t<CompatibleType>,
 | 
			
		||||
             detail::enable_if_t<not std::is_base_of<std::istream, U>::value and
 | 
			
		||||
                                 not std::is_same<U, basic_json_t>::value and
 | 
			
		||||
                                 not detail::is_basic_json_nested_type<
 | 
			
		||||
                                     basic_json_t, U>::value and
 | 
			
		||||
                                 detail::has_to_json<basic_json, U>::value,
 | 
			
		||||
                                 int> = 0>
 | 
			
		||||
    basic_json(CompatibleType && val) noexcept(noexcept(JSONSerializer<U>::to_json(
 | 
			
		||||
                std::declval<basic_json_t&>(), std::forward<CompatibleType>(val))))
 | 
			
		||||
    template <typename CompatibleType,
 | 
			
		||||
              typename U = detail::uncvref_t<CompatibleType>,
 | 
			
		||||
              detail::enable_if_t<
 | 
			
		||||
                  detail::is_compatible_type<basic_json_t, U>::value, int> = 0>
 | 
			
		||||
    basic_json(CompatibleType && val) noexcept(noexcept(
 | 
			
		||||
                JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),
 | 
			
		||||
                                           std::forward<CompatibleType>(val))))
 | 
			
		||||
    {
 | 
			
		||||
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
 | 
			
		||||
        assert_invariant();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										42
									
								
								src/json.hpp
									
										
									
									
									
								
							
							
						
						
									
										42
									
								
								src/json.hpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -312,6 +312,14 @@ template<> struct priority_tag<0> {};
 | 
			
		|||
// has_/is_ functions //
 | 
			
		||||
////////////////////////
 | 
			
		||||
 | 
			
		||||
// source: https://stackoverflow.com/a/37193089/4116453
 | 
			
		||||
 | 
			
		||||
template <typename T, typename = void>
 | 
			
		||||
struct is_complete_type : std::false_type {};
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
 | 
			
		||||
 | 
			
		||||
NLOHMANN_JSON_HAS_HELPER(mapped_type);
 | 
			
		||||
NLOHMANN_JSON_HAS_HELPER(key_type);
 | 
			
		||||
NLOHMANN_JSON_HAS_HELPER(value_type);
 | 
			
		||||
| 
						 | 
				
			
			@ -387,7 +395,6 @@ struct is_compatible_integer_type
 | 
			
		|||
        RealIntegerType, CompatibleNumberIntegerType > ::value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
 | 
			
		||||
template<typename BasicJsonType, typename T>
 | 
			
		||||
struct has_from_json
 | 
			
		||||
| 
						 | 
				
			
			@ -437,6 +444,23 @@ struct has_to_json
 | 
			
		|||
                                      std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename BasicJsonType, typename CompatibleCompleteType>
 | 
			
		||||
struct is_compatible_complete_type
 | 
			
		||||
{
 | 
			
		||||
    static constexpr bool value =
 | 
			
		||||
        not std::is_base_of<std::istream, CompatibleCompleteType>::value and
 | 
			
		||||
        not std::is_same<BasicJsonType, CompatibleCompleteType>::value and
 | 
			
		||||
        not is_basic_json_nested_type<BasicJsonType, CompatibleCompleteType>::value and
 | 
			
		||||
        has_to_json<BasicJsonType, CompatibleCompleteType>::value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename BasicJsonType, typename CompatibleType>
 | 
			
		||||
struct is_compatible_type
 | 
			
		||||
    : conjunction<is_complete_type<CompatibleType>,
 | 
			
		||||
      is_compatible_complete_type<BasicJsonType, CompatibleType>>
 | 
			
		||||
{
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// taken from ranges-v3
 | 
			
		||||
template<typename T>
 | 
			
		||||
struct static_const
 | 
			
		||||
| 
						 | 
				
			
			@ -8839,15 +8863,13 @@ class basic_json
 | 
			
		|||
 | 
			
		||||
    @since version 2.1.0
 | 
			
		||||
    */
 | 
			
		||||
    template<typename CompatibleType, typename U = detail::uncvref_t<CompatibleType>,
 | 
			
		||||
             detail::enable_if_t<not std::is_base_of<std::istream, U>::value and
 | 
			
		||||
                                 not std::is_same<U, basic_json_t>::value and
 | 
			
		||||
                                 not detail::is_basic_json_nested_type<
 | 
			
		||||
                                     basic_json_t, U>::value and
 | 
			
		||||
                                 detail::has_to_json<basic_json, U>::value,
 | 
			
		||||
                                 int> = 0>
 | 
			
		||||
    basic_json(CompatibleType && val) noexcept(noexcept(JSONSerializer<U>::to_json(
 | 
			
		||||
                std::declval<basic_json_t&>(), std::forward<CompatibleType>(val))))
 | 
			
		||||
    template <typename CompatibleType,
 | 
			
		||||
              typename U = detail::uncvref_t<CompatibleType>,
 | 
			
		||||
              detail::enable_if_t<
 | 
			
		||||
                  detail::is_compatible_type<basic_json_t, U>::value, int> = 0>
 | 
			
		||||
    basic_json(CompatibleType && val) noexcept(noexcept(
 | 
			
		||||
                JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),
 | 
			
		||||
                                           std::forward<CompatibleType>(val))))
 | 
			
		||||
    {
 | 
			
		||||
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
 | 
			
		||||
        assert_invariant();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -692,3 +692,22 @@ TEST_CASE("custom serializer that does adl by default", "[udt]")
 | 
			
		|||
    CHECK(me == j.get<udt::person>());
 | 
			
		||||
    CHECK(me == cj.get<udt::person>());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace
 | 
			
		||||
{
 | 
			
		||||
struct incomplete;
 | 
			
		||||
 | 
			
		||||
// std::is_constructible is broken on macOS' libc++
 | 
			
		||||
// use the cppreference implementation
 | 
			
		||||
 | 
			
		||||
template <typename T, typename = void>
 | 
			
		||||
struct is_constructible_patched : std::false_type {};
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct is_constructible_patched<T, decltype(void(json(std::declval<T>())))> : std::true_type {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("an incomplete type does not trigger a compiler error in non-evaluated context", "[udt]")
 | 
			
		||||
{
 | 
			
		||||
    static_assert(not is_constructible_patched<json, incomplete>::value, "");
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue