From 03b391c37bb234c23c2c993057ff4be64efc7883 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= <theo@tanker.io>
Date: Thu, 20 Oct 2016 18:02:07 +0200
Subject: [PATCH] remove has_destructor and has_json_traits, use decltype
 instead

---
 src/json.hpp | 45 ++++++++++++---------------------------------
 1 file changed, 12 insertions(+), 33 deletions(-)

diff --git a/src/json.hpp b/src/json.hpp
index 528c92b2..390d4e79 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -161,26 +161,6 @@ struct has_mapped_type
         std::is_integral<decltype(detect(std::declval<T>()))>::value;
 };
 
-// taken from http://stackoverflow.com/questions/10711952/how-to-detect-existence-of-a-class-using-sfinae
-// used to determine if json_traits is defined for a given type T
-template <typename T>
-struct has_destructor
-{
-  template <typename U>
-  static std::true_type detect(decltype(std::declval<U>().~U())*);
-
-  template <typename>
-  static std::false_type detect(...);
-
-  static constexpr bool value = decltype(detect<T>(0))::value;
-};
-
-template<typename T>
-struct has_json_traits
-{
-  static constexpr bool value = has_destructor<json_traits<T>>::value;
-};
-
 struct to_json_fn
 {
   template <typename T>
@@ -1407,8 +1387,7 @@ class basic_json
     // auto j = json{{"a", json(not_equality_comparable{})}};
     // 
     // we can remove this constraint though, since lots of ctor are not explicit already
-    template <typename T, typename = enable_if_t<
-                              detail::has_json_traits<uncvref_t<T>>::value>>
+    template <typename T, typename = decltype(json_traits<uncvref_t<T>>::to_json(std::declval<uncvref_t<T>>()))>
     explicit basic_json(T &&val)
         : basic_json(json_traits<uncvref_t<T>>::to_json(std::forward<T>(val)))
     {
@@ -2775,24 +2754,19 @@ class basic_json
 
     // get_impl overload chosen if json_traits struct is specialized for type T
     // simply returns json_traits<T>::from_json(*this);
-    template <typename T, typename = enable_if_t<
-                              detail::has_json_traits<uncvref_t<T>>::value>>
-    auto get_impl(T *) const -> decltype(
-        json_traits<uncvref_t<T>>::from_json(std::declval<basic_json>()))
+    // dual argument to avoid conflicting with get_impl overloads taking a pointer
+    template <typename T>
+    auto get_impl(int, int) const -> decltype(json_traits<uncvref_t<T>>::from_json(*this))
     {
       return json_traits<uncvref_t<T>>::from_json(*this);
     }
 
-    // this one is quite atrocious
     // this overload is chosen ONLY if json_traits struct is not specialized, and if the expression nlohmann::from_json(*this, T&) is valid
     // I chose to prefer the json_traits specialization if it exists, since it's a more advanced use.
     // But we can of course change this behaviour
     template <typename T>
-    auto get_impl(T *) const -> enable_if_t<
-        not detail::has_json_traits<remove_cv_t<T>>::value,
-        uncvref_t<decltype(::nlohmann::from_json(std::declval<basic_json>(),
-                                                 std::declval<T &>()),
-                           std::declval<T>())>>
+    auto get_impl(long, long) const -> uncvref_t<decltype(::nlohmann::from_json(*this, std::declval<T &>()),
+                                                    std::declval<T>())>
     {
       remove_cv_t<T> ret;
       // I guess this output parameter is the only way to get ADL
@@ -3108,11 +3082,16 @@ class basic_json
     */
     template<typename ValueType, typename std::enable_if<
                  not std::is_pointer<ValueType>::value, int>::type = 0>
-    ValueType get() const
+    auto get() const -> decltype(get_impl(static_cast<ValueType*>(nullptr)))
     {
         return get_impl(static_cast<ValueType*>(nullptr));
     }
 
+    template <typename ValueType>
+    auto get() const -> decltype(get_impl<ValueType>(0, 0))
+    {
+        return get_impl<ValueType>(0, 0);
+    }
     /*!
     @brief get a pointer value (explicit)