From f665a9233062397c9e713bbac1ff63f5f0a6fe45 Mon Sep 17 00:00:00 2001
From: David Avedissian <git@dga.me.uk>
Date: Wed, 7 Nov 2018 18:39:25 +0000
Subject: [PATCH 1/3] Implement SFINAE friendly iterator_traits and use that
 instead.

---
 .../nlohmann/detail/input/input_adapters.hpp  |  6 +-
 .../detail/iterators/iterator_traits.hpp      | 47 ++++++++++++
 include/nlohmann/detail/meta/type_traits.hpp  |  9 ++-
 include/nlohmann/json.hpp                     |  2 +-
 single_include/nlohmann/json.hpp              | 76 ++++++++++++++++---
 5 files changed, 120 insertions(+), 20 deletions(-)
 create mode 100644 include/nlohmann/detail/iterators/iterator_traits.hpp

diff --git a/include/nlohmann/detail/input/input_adapters.hpp b/include/nlohmann/detail/input/input_adapters.hpp
index 79a19c17..1d549ecc 100644
--- a/include/nlohmann/detail/input/input_adapters.hpp
+++ b/include/nlohmann/detail/input/input_adapters.hpp
@@ -331,7 +331,7 @@ class input_adapter
     /// input adapter for iterator range with contiguous storage
     template<class IteratorType,
              typename std::enable_if<
-                 std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,
+                 std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,
                  int>::type = 0>
     input_adapter(IteratorType first, IteratorType last)
     {
@@ -350,7 +350,7 @@ class input_adapter
 
         // assertion to check that each element is 1 byte long
         static_assert(
-            sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1,
+            sizeof(typename iterator_traits<IteratorType>::value_type) == 1,
             "each element in the iterator range must have the size of 1 byte");
 
         const auto len = static_cast<size_t>(std::distance(first, last));
@@ -374,7 +374,7 @@ class input_adapter
     /// input adapter for contiguous container
     template<class ContiguousContainer, typename
              std::enable_if<not std::is_pointer<ContiguousContainer>::value and
-                            std::is_base_of<std::random_access_iterator_tag, typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value,
+                            std::is_base_of<std::random_access_iterator_tag, typename iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value,
                             int>::type = 0>
     input_adapter(const ContiguousContainer& c)
         : input_adapter(std::begin(c), std::end(c)) {}
diff --git a/include/nlohmann/detail/iterators/iterator_traits.hpp b/include/nlohmann/detail/iterators/iterator_traits.hpp
new file mode 100644
index 00000000..43603988
--- /dev/null
+++ b/include/nlohmann/detail/iterators/iterator_traits.hpp
@@ -0,0 +1,47 @@
+#pragma once
+
+#include <iterator> // random_access_iterator_tag
+
+#include <nlohmann/detail/meta/void_t.hpp>
+
+namespace nlohmann
+{
+namespace detail
+{
+template <class It, class = void>
+struct _iterator_types {};
+
+template <class It>
+struct _iterator_types<
+    It,
+    void_t<typename It::difference_type, typename It::value_type, typename It::pointer,
+           typename It::reference, typename It::iterator_category>> {
+  using difference_type = typename It::difference_type;
+  using value_type = typename It::value_type;
+  using pointer = typename It::pointer;
+  using reference = typename It::reference;
+  using iterator_category = typename It::iterator_category;
+};
+
+template <class Iter>
+struct iterator_traits : _iterator_types<Iter> {};
+
+template <class T>
+struct iterator_traits<T*> {
+  typedef std::random_access_iterator_tag iterator_category;
+  typedef T value_type;
+  typedef ptrdiff_t difference_type;
+  typedef T* pointer;
+  typedef T& reference;
+};
+
+template <class T>
+struct iterator_traits<const T*> {
+  typedef std::random_access_iterator_tag iterator_category;
+  typedef T value_type;
+  typedef ptrdiff_t difference_type;
+  typedef const T* pointer;
+  typedef const T& reference;
+};
+}
+}
\ No newline at end of file
diff --git a/include/nlohmann/detail/meta/type_traits.hpp b/include/nlohmann/detail/meta/type_traits.hpp
index d901f1e0..ee04da22 100644
--- a/include/nlohmann/detail/meta/type_traits.hpp
+++ b/include/nlohmann/detail/meta/type_traits.hpp
@@ -6,6 +6,7 @@
 #include <utility> // declval
 
 #include <nlohmann/json_fwd.hpp>
+#include <nlohmann/detail/iterators/iterator_traits.hpp>
 #include <nlohmann/detail/meta/cpp_future.hpp>
 #include <nlohmann/detail/meta/detected.hpp>
 #include <nlohmann/detail/macro_scope.hpp>
@@ -131,10 +132,10 @@ template <typename T, typename = void>
 struct is_iterator_traits : std::false_type {};
 
 template <typename T>
-struct is_iterator_traits<std::iterator_traits<T>>
+struct is_iterator_traits<iterator_traits<T>>
 {
   private:
-    using traits = std::iterator_traits<T>;
+    using traits = iterator_traits<T>;
 
   public:
     static constexpr auto value =
@@ -251,7 +252,7 @@ struct is_compatible_array_type_impl <
 // Therefore it is detected as a CompatibleArrayType.
 // The real fix would be to have an Iterable concept.
     not is_iterator_traits<
-    std::iterator_traits<CompatibleArrayType>>::value >>
+    iterator_traits<CompatibleArrayType>>::value >>
 {
     static constexpr bool value =
         std::is_constructible<BasicJsonType,
@@ -288,7 +289,7 @@ struct is_constructible_array_type_impl <
         // Therefore it is detected as a ConstructibleArrayType.
         // The real fix would be to have an Iterable concept.
         not is_iterator_traits <
-        std::iterator_traits<ConstructibleArrayType >>::value and
+        iterator_traits<ConstructibleArrayType >>::value and
 
         (std::is_same<typename ConstructibleArrayType::value_type, typename BasicJsonType::array_t::value_type>::value or
          has_from_json<BasicJsonType,
diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp
index 30e69895..cbb00e03 100644
--- a/include/nlohmann/json.hpp
+++ b/include/nlohmann/json.hpp
@@ -41,7 +41,7 @@ SOFTWARE.
 #include <functional> // hash, less
 #include <initializer_list> // initializer_list
 #include <iosfwd> // istream, ostream
-#include <iterator> // iterator_traits, random_access_iterator_tag
+#include <iterator> // random_access_iterator_tag
 #include <numeric> // accumulate
 #include <string> // string, stoi, to_string
 #include <utility> // declval, forward, move, pair, swap
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index 1e7cf51e..8ef906d6 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -41,7 +41,7 @@ SOFTWARE.
 #include <functional> // hash, less
 #include <initializer_list> // initializer_list
 #include <iosfwd> // istream, ostream
-#include <iterator> // iterator_traits, random_access_iterator_tag
+#include <iterator> // random_access_iterator_tag
 #include <numeric> // accumulate
 #include <string> // string, stoi, to_string
 #include <utility> // declval, forward, move, pair, swap
@@ -324,12 +324,10 @@ constexpr T static_const<T>::value;
 
 // #include <nlohmann/json_fwd.hpp>
 
-// #include <nlohmann/detail/meta/cpp_future.hpp>
-
-// #include <nlohmann/detail/meta/detected.hpp>
+// #include <nlohmann/detail/iterators/iterator_traits.hpp>
 
 
-#include <type_traits>
+#include <iterator> // random_access_iterator_tag
 
 // #include <nlohmann/detail/meta/void_t.hpp>
 
@@ -347,6 +345,60 @@ template <typename ...Ts> using void_t = typename make_void<Ts...>::type;
 }  // namespace nlohmann
 
 
+namespace nlohmann
+{
+namespace detail
+{
+template <class It, class = void>
+struct _iterator_types {};
+
+template <class It>
+struct _iterator_types <
+    It,
+    void_t<typename It::difference_type, typename It::value_type, typename It::pointer,
+    typename It::reference, typename It::iterator_category >>
+{
+    using difference_type = typename It::difference_type;
+    using value_type = typename It::value_type;
+    using pointer = typename It::pointer;
+    using reference = typename It::reference;
+    using iterator_category = typename It::iterator_category;
+};
+
+template <class Iter>
+struct iterator_traits : _iterator_types<Iter> {};
+
+template <class T>
+struct iterator_traits<T*>
+{
+    typedef std::random_access_iterator_tag iterator_category;
+    typedef T value_type;
+    typedef ptrdiff_t difference_type;
+    typedef T* pointer;
+    typedef T& reference;
+};
+
+template <class T>
+struct iterator_traits<const T*>
+{
+    typedef std::random_access_iterator_tag iterator_category;
+    typedef T value_type;
+    typedef ptrdiff_t difference_type;
+    typedef const T* pointer;
+    typedef const T& reference;
+};
+}
+}
+// #include <nlohmann/detail/meta/cpp_future.hpp>
+
+// #include <nlohmann/detail/meta/detected.hpp>
+
+
+#include <type_traits>
+
+// #include <nlohmann/detail/meta/void_t.hpp>
+
+
 // http://en.cppreference.com/w/cpp/experimental/is_detected
 namespace nlohmann
 {
@@ -522,10 +574,10 @@ template <typename T, typename = void>
 struct is_iterator_traits : std::false_type {};
 
 template <typename T>
-struct is_iterator_traits<std::iterator_traits<T>>
+struct is_iterator_traits<iterator_traits<T>>
 {
   private:
-    using traits = std::iterator_traits<T>;
+    using traits = iterator_traits<T>;
 
   public:
     static constexpr auto value =
@@ -642,7 +694,7 @@ struct is_compatible_array_type_impl <
 // Therefore it is detected as a CompatibleArrayType.
 // The real fix would be to have an Iterable concept.
     not is_iterator_traits<
-    std::iterator_traits<CompatibleArrayType>>::value >>
+    iterator_traits<CompatibleArrayType>>::value >>
 {
     static constexpr bool value =
         std::is_constructible<BasicJsonType,
@@ -679,7 +731,7 @@ struct is_constructible_array_type_impl <
         // Therefore it is detected as a ConstructibleArrayType.
         // The real fix would be to have an Iterable concept.
         not is_iterator_traits <
-        std::iterator_traits<ConstructibleArrayType >>::value and
+        iterator_traits<ConstructibleArrayType >>::value and
 
         (std::is_same<typename ConstructibleArrayType::value_type, typename BasicJsonType::array_t::value_type>::value or
          has_from_json<BasicJsonType,
@@ -2380,7 +2432,7 @@ class input_adapter
     /// input adapter for iterator range with contiguous storage
     template<class IteratorType,
              typename std::enable_if<
-                 std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,
+                 std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,
                  int>::type = 0>
     input_adapter(IteratorType first, IteratorType last)
     {
@@ -2399,7 +2451,7 @@ class input_adapter
 
         // assertion to check that each element is 1 byte long
         static_assert(
-            sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1,
+            sizeof(typename iterator_traits<IteratorType>::value_type) == 1,
             "each element in the iterator range must have the size of 1 byte");
 
         const auto len = static_cast<size_t>(std::distance(first, last));
@@ -2423,7 +2475,7 @@ class input_adapter
     /// input adapter for contiguous container
     template<class ContiguousContainer, typename
              std::enable_if<not std::is_pointer<ContiguousContainer>::value and
-                            std::is_base_of<std::random_access_iterator_tag, typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value,
+                            std::is_base_of<std::random_access_iterator_tag, typename iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value,
                             int>::type = 0>
     input_adapter(const ContiguousContainer& c)
         : input_adapter(std::begin(c), std::end(c)) {}

From 2c23f0a34600ce54a1687004b9557079046e5b6e Mon Sep 17 00:00:00 2001
From: David Avedissian <git@dga.me.uk>
Date: Sat, 8 Dec 2018 15:46:33 +0000
Subject: [PATCH 2/3] Changes requested from code review.

---
 .../detail/iterators/iterator_traits.hpp      | 36 +++++++++---------
 single_include/nlohmann/json.hpp              | 38 ++++++++++---------
 2 files changed, 39 insertions(+), 35 deletions(-)

diff --git a/include/nlohmann/detail/iterators/iterator_traits.hpp b/include/nlohmann/detail/iterators/iterator_traits.hpp
index 43603988..607dd49a 100644
--- a/include/nlohmann/detail/iterators/iterator_traits.hpp
+++ b/include/nlohmann/detail/iterators/iterator_traits.hpp
@@ -3,16 +3,17 @@
 #include <iterator> // random_access_iterator_tag
 
 #include <nlohmann/detail/meta/void_t.hpp>
+#include <nlohmann/detail/meta/cpp_future.hpp>
 
 namespace nlohmann
 {
 namespace detail
 {
-template <class It, class = void>
-struct _iterator_types {};
+template <typename It, typename = void>
+struct iterator_types {};
 
-template <class It>
-struct _iterator_types<
+template <typename It>
+struct iterator_types<
     It,
     void_t<typename It::difference_type, typename It::value_type, typename It::pointer,
            typename It::reference, typename It::iterator_category>> {
@@ -23,25 +24,26 @@ struct _iterator_types<
   using iterator_category = typename It::iterator_category;
 };
 
-template <class Iter>
-struct iterator_traits : _iterator_types<Iter> {};
+// This is required as some compilers implement std::iterator_traits in a way that
+// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341.
+template <typename T, typename = void>
+struct iterator_traits
+{
+};
 
-template <class T>
-struct iterator_traits<T*> {
+template <typename T>
+struct iterator_traits<T, enable_if_t<!std::is_pointer<T>::value>>
+  : iterator_types<T>
+{
+};
+
+template <typename T>
+struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>> {
   typedef std::random_access_iterator_tag iterator_category;
   typedef T value_type;
   typedef ptrdiff_t difference_type;
   typedef T* pointer;
   typedef T& reference;
 };
-
-template <class T>
-struct iterator_traits<const T*> {
-  typedef std::random_access_iterator_tag iterator_category;
-  typedef T value_type;
-  typedef ptrdiff_t difference_type;
-  typedef const T* pointer;
-  typedef const T& reference;
-};
 }
 }
\ No newline at end of file
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index 8ef906d6..24ff17b8 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -344,16 +344,18 @@ template <typename ...Ts> using void_t = typename make_void<Ts...>::type;
 } // namespace detail
 }  // namespace nlohmann
 
+// #include <nlohmann/detail/meta/cpp_future.hpp>
+
 
 namespace nlohmann
 {
 namespace detail
 {
-template <class It, class = void>
-struct _iterator_types {};
+template <typename It, typename = void>
+struct iterator_types {};
 
-template <class It>
-struct _iterator_types <
+template <typename It>
+struct iterator_types <
     It,
     void_t<typename It::difference_type, typename It::value_type, typename It::pointer,
     typename It::reference, typename It::iterator_category >>
@@ -365,11 +367,21 @@ struct _iterator_types <
     using iterator_category = typename It::iterator_category;
 };
 
-template <class Iter>
-struct iterator_traits : _iterator_types<Iter> {};
+// This is required due to https://github.com/nlohmann/json/issues/1341 - where some
+// compilers implement std::iterator_traits in a way that doesn't work with SFINAE.
+template <typename T, typename = void>
+struct iterator_traits
+{
+};
 
-template <class T>
-struct iterator_traits<T*>
+template <typename T>
+struct iterator_traits < T, enable_if_t < !std::is_pointer<T>::value >>
+            : iterator_types<T>
+{
+};
+
+template <typename T>
+struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>>
 {
     typedef std::random_access_iterator_tag iterator_category;
     typedef T value_type;
@@ -377,16 +389,6 @@ struct iterator_traits<T*>
     typedef T* pointer;
     typedef T& reference;
 };
-
-template <class T>
-struct iterator_traits<const T*>
-{
-    typedef std::random_access_iterator_tag iterator_category;
-    typedef T value_type;
-    typedef ptrdiff_t difference_type;
-    typedef const T* pointer;
-    typedef const T& reference;
-};
 }
 }
 // #include <nlohmann/detail/meta/cpp_future.hpp>

From f1080d7c396d692067384257f87c9feee98a6a98 Mon Sep 17 00:00:00 2001
From: David Avedissian <git@dga.me.uk>
Date: Tue, 18 Dec 2018 20:44:37 +0000
Subject: [PATCH 3/3] Code review.

---
 .../nlohmann/detail/iterators/iterator_traits.hpp | 12 ++++++------
 single_include/nlohmann/json.hpp                  | 15 ++++++++-------
 2 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/include/nlohmann/detail/iterators/iterator_traits.hpp b/include/nlohmann/detail/iterators/iterator_traits.hpp
index 607dd49a..35ea81fb 100644
--- a/include/nlohmann/detail/iterators/iterator_traits.hpp
+++ b/include/nlohmann/detail/iterators/iterator_traits.hpp
@@ -39,11 +39,11 @@ struct iterator_traits<T, enable_if_t<!std::is_pointer<T>::value>>
 
 template <typename T>
 struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>> {
-  typedef std::random_access_iterator_tag iterator_category;
-  typedef T value_type;
-  typedef ptrdiff_t difference_type;
-  typedef T* pointer;
-  typedef T& reference;
+  using iterator_category = std::random_access_iterator_tag;
+  using value_type = T;
+  using difference_type = ptrdiff_t;
+  using pointer = T*;
+  using reference = T&;
 };
 }
-}
\ No newline at end of file
+}
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index 24ff17b8..2d7e1ddd 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -367,8 +367,8 @@ struct iterator_types <
     using iterator_category = typename It::iterator_category;
 };
 
-// This is required due to https://github.com/nlohmann/json/issues/1341 - where some
-// compilers implement std::iterator_traits in a way that doesn't work with SFINAE.
+// This is required as some compilers implement std::iterator_traits in a way that
+// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341.
 template <typename T, typename = void>
 struct iterator_traits
 {
@@ -383,14 +383,15 @@ struct iterator_traits < T, enable_if_t < !std::is_pointer<T>::value >>
 template <typename T>
 struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>>
 {
-    typedef std::random_access_iterator_tag iterator_category;
-    typedef T value_type;
-    typedef ptrdiff_t difference_type;
-    typedef T* pointer;
-    typedef T& reference;
+    using iterator_category = std::random_access_iterator_tag;
+    using value_type = T;
+    using difference_type = ptrdiff_t;
+    using pointer = T*;
+    using reference = T&;
 };
 }
 }
+
 // #include <nlohmann/detail/meta/cpp_future.hpp>
 
 // #include <nlohmann/detail/meta/detected.hpp>