From c833b22b7b94e7cd4d5a24e8280ec9d8c0890097 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= <theo@tanker.io>
Date: Sat, 7 Jan 2017 16:57:52 +0100
Subject: [PATCH] move type_name outside of basic_json, make it a friend

---
 src/json.hpp      | 43 +++++++++++++++++++++++--------------------
 src/json.hpp.re2c | 43 +++++++++++++++++++++++--------------------
 2 files changed, 46 insertions(+), 40 deletions(-)

diff --git a/src/json.hpp b/src/json.hpp
index cc397e39..3b00d80e 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -181,6 +181,27 @@ using is_unscoped_enum =
 
 namespace detail
 {
+template <typename Json> std::string type_name(Json const &j)
+{
+  switch (j.m_type)
+  {
+  case value_t::null:
+    return "null";
+  case value_t::object:
+    return "object";
+  case value_t::array:
+    return "array";
+  case value_t::string:
+    return "string";
+  case value_t::boolean:
+    return "boolean";
+  case value_t::discarded:
+    return "discarded";
+  default:
+    return "number";
+  }
+}
+
 // very useful construct against boilerplate (more boilerplate needed than in
 // C++17: http://en.cppreference.com/w/cpp/types/void_t)
 template <typename...> struct make_void
@@ -585,6 +606,7 @@ template <
 class basic_json
 {
   private:
+    template <typename Json> friend std::string detail::type_name(Json const &);
     /// workaround type for MSVC
     using basic_json_t = basic_json<ObjectType, ArrayType, StringType,
           BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType,
@@ -8129,26 +8151,7 @@ class basic_json
 
     @since version 1.0.0
     */
-    std::string type_name() const
-    {
-        switch (m_type)
-        {
-            case value_t::null:
-                return "null";
-            case value_t::object:
-                return "object";
-            case value_t::array:
-                return "array";
-            case value_t::string:
-                return "string";
-            case value_t::boolean:
-                return "boolean";
-            case value_t::discarded:
-                return "discarded";
-            default:
-                return "number";
-        }
-    }
+    std::string type_name() const { return detail::type_name(*this); }
 
   private:
     /*!
diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c
index 15714669..ed9075ac 100644
--- a/src/json.hpp.re2c
+++ b/src/json.hpp.re2c
@@ -181,6 +181,27 @@ using is_unscoped_enum =
 
 namespace detail
 {
+template <typename Json> std::string type_name(Json const &j)
+{
+  switch (j.m_type)
+  {
+  case value_t::null:
+    return "null";
+  case value_t::object:
+    return "object";
+  case value_t::array:
+    return "array";
+  case value_t::string:
+    return "string";
+  case value_t::boolean:
+    return "boolean";
+  case value_t::discarded:
+    return "discarded";
+  default:
+    return "number";
+  }
+}
+
 // very useful construct against boilerplate (more boilerplate needed than in
 // C++17: http://en.cppreference.com/w/cpp/types/void_t)
 template <typename...> struct make_void
@@ -586,6 +607,7 @@ template <
 class basic_json
 {
   private:
+    template <typename Json> friend std::string detail::type_name(Json const &);
     /// workaround type for MSVC
     using basic_json_t = basic_json<ObjectType, ArrayType, StringType,
           BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType,
@@ -8127,26 +8149,7 @@ class basic_json
 
     @since version 1.0.0
     */
-    std::string type_name() const
-    {
-        switch (m_type)
-        {
-            case value_t::null:
-                return "null";
-            case value_t::object:
-                return "object";
-            case value_t::array:
-                return "array";
-            case value_t::string:
-                return "string";
-            case value_t::boolean:
-                return "boolean";
-            case value_t::discarded:
-                return "discarded";
-            default:
-                return "number";
-        }
-    }
+    std::string type_name() const { return detail::type_name(*this); }
 
   private:
     /*!