فهرست منبع

Simplified implementation of comparison operators

Benoit Blanchon 5 سال پیش
والد
کامیت
0e794a28a1

+ 1 - 0
src/ArduinoJson.hpp

@@ -28,6 +28,7 @@
 #include "ArduinoJson/Object/MemberProxy.hpp"
 #include "ArduinoJson/Object/ObjectImpl.hpp"
 #include "ArduinoJson/Variant/VariantAsImpl.hpp"
+#include "ArduinoJson/Variant/VariantCompare.hpp"
 #include "ArduinoJson/Variant/VariantImpl.hpp"
 
 #include "ArduinoJson/Json/JsonDeserializer.hpp"

+ 8 - 1
src/ArduinoJson/Array/ElementProxy.hpp

@@ -5,7 +5,8 @@
 #pragma once
 
 #include <ArduinoJson/Configuration.hpp>
-#include <ArduinoJson/Operators/VariantOperators.hpp>
+#include <ArduinoJson/Variant/VariantOperators.hpp>
+#include <ArduinoJson/Variant/VariantShortcuts.hpp>
 #include <ArduinoJson/Variant/VariantTo.hpp>
 
 #ifdef _MSC_VER
@@ -17,6 +18,7 @@ namespace ARDUINOJSON_NAMESPACE {
 
 template <typename TArray>
 class ElementProxy : public VariantOperators<ElementProxy<TArray> >,
+                     public VariantShortcuts<ElementProxy<TArray> >,
                      public Visitable {
   typedef ElementProxy<TArray> this_type;
 
@@ -77,6 +79,11 @@ class ElementProxy : public VariantOperators<ElementProxy<TArray> >,
     return getUpstreamElement();
   }
 
+  template <typename T>
+  FORCE_INLINE int compare(const T& rhs) const {
+    return getUpstreamElement().template compare<T>(rhs);
+  }
+
   template <typename T>
   FORCE_INLINE bool is() const {
     return getUpstreamElement().template is<T>();

+ 8 - 1
src/ArduinoJson/Object/MemberProxy.hpp

@@ -5,9 +5,10 @@
 #pragma once
 
 #include <ArduinoJson/Configuration.hpp>
-#include <ArduinoJson/Operators/VariantOperators.hpp>
 #include <ArduinoJson/Polyfills/type_traits.hpp>
+#include <ArduinoJson/Variant/VariantOperators.hpp>
 #include <ArduinoJson/Variant/VariantRef.hpp>
+#include <ArduinoJson/Variant/VariantShortcuts.hpp>
 #include <ArduinoJson/Variant/VariantTo.hpp>
 
 #ifdef _MSC_VER
@@ -19,6 +20,7 @@ namespace ARDUINOJSON_NAMESPACE {
 
 template <typename TObject, typename TStringRef>
 class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef> >,
+                    public VariantShortcuts<MemberProxy<TObject, TStringRef> >,
                     public Visitable {
   typedef MemberProxy<TObject, TStringRef> this_type;
 
@@ -80,6 +82,11 @@ class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef> >,
     return getUpstreamMember();
   }
 
+  template <typename T>
+  FORCE_INLINE int compare(const T &rhs) const {
+    return getUpstreamMember().template compare<T>(rhs);
+  }
+
   template <typename TValue>
   FORCE_INLINE bool is() const {
     return getUpstreamMember().template is<TValue>();

+ 0 - 255
src/ArduinoJson/Operators/VariantComparisons.hpp

@@ -1,255 +0,0 @@
-// ArduinoJson - arduinojson.org
-// Copyright Benoit Blanchon 2014-2020
-// MIT License
-
-#pragma once
-
-#include <ArduinoJson/Configuration.hpp>
-#include <ArduinoJson/Misc/Visitable.hpp>
-#include <ArduinoJson/Numbers/Float.hpp>
-#include <ArduinoJson/Numbers/Integer.hpp>
-#include <ArduinoJson/Polyfills/type_traits.hpp>
-#include <ArduinoJson/Strings/IsString.hpp>
-
-namespace ARDUINOJSON_NAMESPACE {
-
-class CollectionData;
-
-template <typename T, typename Enable = void>
-struct Comparer;
-
-template <typename T>
-struct Comparer<T, typename enable_if<IsString<T>::value>::type> {
-  T rhs;
-  int result;
-
-  explicit Comparer(T value) : rhs(value), result(1) {}
-
-  void visitArray(const CollectionData &) {}
-  void visitObject(const CollectionData &) {}
-  void visitFloat(Float) {}
-  void visitString(const char *lhs) {
-    result = -adaptString(rhs).compare(lhs);
-  }
-  void visitRawJson(const char *, size_t) {}
-  void visitNegativeInteger(UInt) {}
-  void visitPositiveInteger(UInt) {}
-  void visitBoolean(bool) {}
-  void visitNull() {
-    result = adaptString(rhs).compare(NULL);
-  }
-};
-
-template <typename T>
-typename enable_if<is_signed<T>::value, int>::type sign(const T &value) {
-  return value < 0 ? -1 : value > 0 ? 1 : 0;
-}
-
-template <typename T>
-typename enable_if<is_unsigned<T>::value, int>::type sign(const T &value) {
-  return value > 0 ? 1 : 0;
-}
-
-template <typename T>
-struct Comparer<T, typename enable_if<is_integral<T>::value ||
-                                      is_floating_point<T>::value>::type> {
-  T rhs;
-  int result;
-
-  explicit Comparer(T value) : rhs(value), result(1) {}
-
-  void visitArray(const CollectionData &) {}
-  void visitObject(const CollectionData &) {}
-  void visitFloat(Float lhs) {
-    result = sign(lhs - static_cast<Float>(rhs));
-  }
-  void visitString(const char *) {}
-  void visitRawJson(const char *, size_t) {}
-  void visitNegativeInteger(UInt lhs) {
-    result = -sign(static_cast<T>(lhs) + rhs);
-  }
-  void visitPositiveInteger(UInt lhs) {
-    result = static_cast<T>(lhs) < rhs ? -1 : static_cast<T>(lhs) > rhs ? 1 : 0;
-  }
-  void visitBoolean(bool) {}
-  void visitNull() {}
-};
-
-template <>
-struct Comparer<bool, void> {
-  bool rhs;
-  int result;
-
-  explicit Comparer(bool value) : rhs(value), result(1) {}
-
-  void visitArray(const CollectionData &) {}
-  void visitObject(const CollectionData &) {}
-  void visitFloat(Float) {}
-  void visitString(const char *) {}
-  void visitRawJson(const char *, size_t) {}
-  void visitNegativeInteger(UInt) {}
-  void visitPositiveInteger(UInt) {}
-  void visitBoolean(bool lhs) {
-    result = static_cast<int>(lhs - rhs);
-  }
-  void visitNull() {}
-};
-
-#if ARDUINOJSON_HAS_NULLPTR
-template <>
-struct Comparer<decltype(nullptr), void> {
-  int result;
-
-  explicit Comparer(decltype(nullptr)) : result(1) {}
-
-  void visitArray(const CollectionData &) {}
-  void visitObject(const CollectionData &) {}
-  void visitFloat(Float) {}
-  void visitString(const char *) {}
-  void visitRawJson(const char *, size_t) {}
-  void visitNegativeInteger(UInt) {}
-  void visitPositiveInteger(UInt) {}
-  void visitBoolean(bool) {}
-  void visitNull() {
-    result = 0;
-  }
-};
-#endif
-
-template <typename TVariant>
-class VariantComparisons {
- private:
-  template <typename T>
-  static int compare(TVariant lhs, const T &rhs) {
-    Comparer<T> comparer(rhs);
-    lhs.accept(comparer);
-    return comparer.result;
-  }
-
- public:
-  // value == TVariant
-  template <typename T>
-  friend bool operator==(T *lhs, TVariant rhs) {
-    return compare(rhs, lhs) == 0;
-  }
-  template <typename T>
-  friend typename enable_if<!IsVisitable<T>::value, bool>::type operator==(
-      const T &lhs, TVariant rhs) {
-    return compare(rhs, lhs) == 0;
-  }
-
-  // TVariant == value
-  template <typename T>
-  friend bool operator==(TVariant lhs, T *rhs) {
-    return compare(lhs, rhs) == 0;
-  }
-  template <typename T>
-  friend typename enable_if<!IsVisitable<T>::value, bool>::type operator==(
-      TVariant lhs, const T &rhs) {
-    return compare(lhs, rhs) == 0;
-  }
-
-  // value != TVariant
-  template <typename T>
-  friend bool operator!=(T *lhs, TVariant rhs) {
-    return compare(rhs, lhs) != 0;
-  }
-  template <typename T>
-  friend typename enable_if<!IsVisitable<T>::value, bool>::type operator!=(
-      const T &lhs, TVariant rhs) {
-    return compare(rhs, lhs) != 0;
-  }
-
-  // TVariant != value
-  template <typename T>
-  friend bool operator!=(TVariant lhs, T *rhs) {
-    return compare(lhs, rhs) != 0;
-  }
-  template <typename T>
-  friend typename enable_if<!IsVisitable<T>::value, bool>::type operator!=(
-      TVariant lhs, const T &rhs) {
-    return compare(lhs, rhs) != 0;
-  }
-
-  // value < TVariant
-  template <typename T>
-  friend bool operator<(T *lhs, TVariant rhs) {
-    return compare(rhs, lhs) > 0;
-  }
-  template <typename T>
-  friend bool operator<(const T &lhs, TVariant rhs) {
-    return compare(rhs, lhs) > 0;
-  }
-
-  // TVariant < value
-  template <typename T>
-  friend bool operator<(TVariant lhs, T *rhs) {
-    return compare(lhs, rhs) < 0;
-  }
-  template <typename T>
-  friend bool operator<(TVariant lhs, const T &rhs) {
-    return compare(lhs, rhs) < 0;
-  }
-
-  // value <= TVariant
-  template <typename T>
-  friend bool operator<=(T *lhs, TVariant rhs) {
-    return compare(rhs, lhs) >= 0;
-  }
-  template <typename T>
-  friend bool operator<=(const T &lhs, TVariant rhs) {
-    return compare(rhs, lhs) >= 0;
-  }
-
-  // TVariant <= value
-  template <typename T>
-  friend bool operator<=(TVariant lhs, T *rhs) {
-    return compare(lhs, rhs) <= 0;
-  }
-  template <typename T>
-  friend bool operator<=(TVariant lhs, const T &rhs) {
-    return compare(lhs, rhs) <= 0;
-  }
-
-  // value > TVariant
-  template <typename T>
-  friend bool operator>(T *lhs, TVariant rhs) {
-    return compare(rhs, lhs) < 0;
-  }
-  template <typename T>
-  friend bool operator>(const T &lhs, TVariant rhs) {
-    return compare(rhs, lhs) < 0;
-  }
-
-  // TVariant > value
-  template <typename T>
-  friend bool operator>(TVariant lhs, T *rhs) {
-    return compare(lhs, rhs) > 0;
-  }
-  template <typename T>
-  friend bool operator>(TVariant lhs, const T &rhs) {
-    return compare(lhs, rhs) > 0;
-  }
-
-  // value >= TVariant
-  template <typename T>
-  friend bool operator>=(T *lhs, TVariant rhs) {
-    return compare(rhs, lhs) <= 0;
-  }
-  template <typename T>
-  friend bool operator>=(const T &lhs, TVariant rhs) {
-    return compare(rhs, lhs) <= 0;
-  }
-
-  // TVariant >= value
-  template <typename T>
-  friend bool operator>=(TVariant lhs, T *rhs) {
-    return compare(lhs, rhs) >= 0;
-  }
-  template <typename T>
-  friend bool operator>=(TVariant lhs, const T &rhs) {
-    return compare(lhs, rhs) >= 0;
-  }
-};
-
-}  // namespace ARDUINOJSON_NAMESPACE

+ 0 - 17
src/ArduinoJson/Operators/VariantOperators.hpp

@@ -1,17 +0,0 @@
-// ArduinoJson - arduinojson.org
-// Copyright Benoit Blanchon 2014-2020
-// MIT License
-
-#pragma once
-
-#include <ArduinoJson/Operators/VariantComparisons.hpp>
-#include <ArduinoJson/Operators/VariantOr.hpp>
-#include <ArduinoJson/Operators/VariantShortcuts.hpp>
-
-namespace ARDUINOJSON_NAMESPACE {
-
-template <typename TImpl>
-class VariantOperators : public VariantComparisons<TImpl>,
-                         public VariantOr<TImpl>,
-                         public VariantShortcuts<TImpl> {};
-}  // namespace ARDUINOJSON_NAMESPACE

+ 0 - 37
src/ArduinoJson/Operators/VariantOr.hpp

@@ -1,37 +0,0 @@
-// ArduinoJson - arduinojson.org
-// Copyright Benoit Blanchon 2014-2020
-// MIT License
-
-#pragma once
-
-#include <ArduinoJson/Polyfills/attributes.hpp>
-#include <ArduinoJson/Polyfills/type_traits.hpp>
-#include <ArduinoJson/Variant/VariantAs.hpp>
-
-namespace ARDUINOJSON_NAMESPACE {
-
-template <typename TImpl>
-class VariantOr {
- public:
-  // Returns the default value if the VariantRef is undefined of incompatible
-  template <typename T>
-  T operator|(const T &defaultValue) const {
-    if (impl()->template is<T>())
-      return impl()->template as<T>();
-    else
-      return defaultValue;
-  }
-
-  // Returns the default value if the VariantRef is undefined of incompatible
-  // Special case for string: null is treated as undefined
-  const char *operator|(const char *defaultValue) const {
-    const char *value = impl()->template as<const char *>();
-    return value ? value : defaultValue;
-  }
-
- private:
-  const TImpl *impl() const {
-    return static_cast<const TImpl *>(this);
-  }
-};
-}  // namespace ARDUINOJSON_NAMESPACE

+ 129 - 0
src/ArduinoJson/Variant/VariantCompare.hpp

@@ -0,0 +1,129 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2020
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Configuration.hpp>
+#include <ArduinoJson/Misc/Visitable.hpp>
+#include <ArduinoJson/Numbers/Float.hpp>
+#include <ArduinoJson/Numbers/Integer.hpp>
+#include <ArduinoJson/Polyfills/type_traits.hpp>
+#include <ArduinoJson/Strings/IsString.hpp>
+
+namespace ARDUINOJSON_NAMESPACE {
+
+class CollectionData;
+
+template <typename T, typename Enable = void>
+struct Comparer;
+
+template <typename T>
+struct Comparer<T, typename enable_if<IsString<T>::value>::type> {
+  T rhs;
+  int result;
+
+  explicit Comparer(T value) : rhs(value), result(1) {}
+
+  void visitArray(const CollectionData &) {}
+  void visitObject(const CollectionData &) {}
+  void visitFloat(Float) {}
+  void visitString(const char *lhs) {
+    result = -adaptString(rhs).compare(lhs);
+  }
+  void visitRawJson(const char *, size_t) {}
+  void visitNegativeInteger(UInt) {}
+  void visitPositiveInteger(UInt) {}
+  void visitBoolean(bool) {}
+  void visitNull() {
+    result = adaptString(rhs).compare(NULL);
+  }
+};
+template <typename T>
+typename enable_if<is_signed<T>::value, int>::type sign2(const T &value) {
+  return value < 0 ? -1 : value > 0 ? 1 : 0;
+}
+
+template <typename T>
+typename enable_if<is_unsigned<T>::value, int>::type sign2(const T &value) {
+  return value > 0 ? 1 : 0;
+}
+
+template <typename T>
+struct Comparer<T, typename enable_if<is_integral<T>::value ||
+                                      is_floating_point<T>::value>::type> {
+  T rhs;
+  int result;
+
+  explicit Comparer(T value) : rhs(value), result(1) {}
+
+  void visitArray(const CollectionData &) {}
+  void visitObject(const CollectionData &) {}
+  void visitFloat(Float lhs) {
+    result = sign2(lhs - static_cast<Float>(rhs));
+  }
+  void visitString(const char *) {}
+  void visitRawJson(const char *, size_t) {}
+  void visitNegativeInteger(UInt lhs) {
+    result = -sign2(static_cast<T>(lhs) + rhs);
+  }
+  void visitPositiveInteger(UInt lhs) {
+    result = static_cast<T>(lhs) < rhs ? -1 : static_cast<T>(lhs) > rhs ? 1 : 0;
+  }
+  void visitBoolean(bool) {}
+  void visitNull() {}
+};
+
+template <>
+struct Comparer<bool, void> {
+  bool rhs;
+  int result;
+
+  explicit Comparer(bool value) : rhs(value), result(1) {}
+
+  void visitArray(const CollectionData &) {}
+  void visitObject(const CollectionData &) {}
+  void visitFloat(Float) {}
+  void visitString(const char *) {}
+  void visitRawJson(const char *, size_t) {}
+  void visitNegativeInteger(UInt) {}
+  void visitPositiveInteger(UInt) {}
+  void visitBoolean(bool lhs) {
+    result = static_cast<int>(lhs - rhs);
+  }
+  void visitNull() {}
+};
+
+#if ARDUINOJSON_HAS_NULLPTR
+template <>
+struct Comparer<decltype(nullptr), void> {
+  int result;
+
+  explicit Comparer(decltype(nullptr)) : result(1) {}
+
+  void visitArray(const CollectionData &) {}
+  void visitObject(const CollectionData &) {}
+  void visitFloat(Float) {}
+  void visitString(const char *) {}
+  void visitRawJson(const char *, size_t) {}
+  void visitNegativeInteger(UInt) {}
+  void visitPositiveInteger(UInt) {}
+  void visitBoolean(bool) {}
+  void visitNull() {
+    result = 0;
+  }
+};
+#endif
+
+template <typename TData>
+template <typename T>
+int VariantRefBase<TData>::compare(const T &rhs) const {
+  Comparer<T> comparer(rhs);
+  if (_data)
+    _data->accept(comparer);
+  else
+    comparer.visitNull();
+  return comparer.result;
+}
+
+}  // namespace ARDUINOJSON_NAMESPACE

+ 157 - 0
src/ArduinoJson/Variant/VariantOperators.hpp

@@ -0,0 +1,157 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2020
+// MIT License
+
+#pragma once
+
+#include <ArduinoJson/Misc/Visitable.hpp>
+#include <ArduinoJson/Polyfills/attributes.hpp>
+#include <ArduinoJson/Polyfills/type_traits.hpp>
+#include <ArduinoJson/Variant/VariantAs.hpp>
+
+namespace ARDUINOJSON_NAMESPACE {
+
+template <typename TVariant>
+struct VariantOperators {
+  // Returns the default value if the VariantRef is undefined of incompatible
+  template <typename T>
+  friend T operator|(const TVariant &variant, const T &defaultValue) {
+    if (variant.template is<T>())
+      return variant.template as<T>();
+    else
+      return defaultValue;
+  }
+
+  // Returns the default value if the VariantRef is undefined of incompatible
+  // Special case for string: null is treated as undefined
+  friend const char *operator|(const TVariant &variant,
+                               const char *defaultValue) {
+    const char *value = variant.template as<const char *>();
+    return value ? value : defaultValue;
+  }
+
+  // value == TVariant
+  template <typename T>
+  friend bool operator==(T *lhs, TVariant rhs) {
+    return rhs.compare(lhs) == 0;
+  }
+  template <typename T>
+  friend typename enable_if<!IsVisitable<T>::value, bool>::type operator==(
+      const T &lhs, TVariant rhs) {
+    return rhs.compare(lhs) == 0;
+  }
+
+  // TVariant == value
+  template <typename T>
+  friend bool operator==(TVariant lhs, T *rhs) {
+    return lhs.compare(rhs) == 0;
+  }
+  template <typename T>
+  friend typename enable_if<!IsVisitable<T>::value, bool>::type operator==(
+      TVariant lhs, const T &rhs) {
+    return lhs.compare(rhs) == 0;
+  }
+
+  // value != TVariant
+  template <typename T>
+  friend bool operator!=(T *lhs, TVariant rhs) {
+    return rhs.compare(lhs) != 0;
+  }
+  template <typename T>
+  friend typename enable_if<!IsVisitable<T>::value, bool>::type operator!=(
+      const T &lhs, TVariant rhs) {
+    return rhs.compare(lhs) != 0;
+  }
+
+  // TVariant != value
+  template <typename T>
+  friend bool operator!=(TVariant lhs, T *rhs) {
+    return lhs.compare(rhs) != 0;
+  }
+  template <typename T>
+  friend typename enable_if<!IsVisitable<T>::value, bool>::type operator!=(
+      TVariant lhs, const T &rhs) {
+    return lhs.compare(rhs) != 0;
+  }
+
+  // value < TVariant
+  template <typename T>
+  friend bool operator<(T *lhs, TVariant rhs) {
+    return rhs.compare(lhs) > 0;
+  }
+  template <typename T>
+  friend bool operator<(const T &lhs, TVariant rhs) {
+    return rhs.compare(lhs) > 0;
+  }
+
+  // TVariant < value
+  template <typename T>
+  friend bool operator<(TVariant lhs, T *rhs) {
+    return lhs.compare(rhs) < 0;
+  }
+  template <typename T>
+  friend bool operator<(TVariant lhs, const T &rhs) {
+    return lhs.compare(rhs) < 0;
+  }
+
+  // value <= TVariant
+  template <typename T>
+  friend bool operator<=(T *lhs, TVariant rhs) {
+    return rhs.compare(lhs) >= 0;
+  }
+  template <typename T>
+  friend bool operator<=(const T &lhs, TVariant rhs) {
+    return rhs.compare(lhs) >= 0;
+  }
+
+  // TVariant <= value
+  template <typename T>
+  friend bool operator<=(TVariant lhs, T *rhs) {
+    return lhs.compare(rhs) <= 0;
+  }
+  template <typename T>
+  friend bool operator<=(TVariant lhs, const T &rhs) {
+    return lhs.compare(rhs) <= 0;
+  }
+
+  // value > TVariant
+  template <typename T>
+  friend bool operator>(T *lhs, TVariant rhs) {
+    return rhs.compare(lhs) < 0;
+  }
+  template <typename T>
+  friend bool operator>(const T &lhs, TVariant rhs) {
+    return rhs.compare(lhs) < 0;
+  }
+
+  // TVariant > value
+  template <typename T>
+  friend bool operator>(TVariant lhs, T *rhs) {
+    return lhs.compare(rhs) > 0;
+  }
+  template <typename T>
+  friend bool operator>(TVariant lhs, const T &rhs) {
+    return lhs.compare(rhs) > 0;
+  }
+
+  // value >= TVariant
+  template <typename T>
+  friend bool operator>=(T *lhs, TVariant rhs) {
+    return rhs.compare(lhs) <= 0;
+  }
+  template <typename T>
+  friend bool operator>=(const T &lhs, TVariant rhs) {
+    return rhs.compare(lhs) <= 0;
+  }
+
+  // TVariant >= value
+  template <typename T>
+  friend bool operator>=(TVariant lhs, T *rhs) {
+    return lhs.compare(rhs) >= 0;
+  }
+  template <typename T>
+  friend bool operator>=(TVariant lhs, const T &rhs) {
+    return lhs.compare(rhs) >= 0;
+  }
+};
+}  // namespace ARDUINOJSON_NAMESPACE

+ 7 - 1
src/ArduinoJson/Variant/VariantRef.hpp

@@ -9,11 +9,12 @@
 
 #include <ArduinoJson/Memory/MemoryPool.hpp>
 #include <ArduinoJson/Misc/Visitable.hpp>
-#include <ArduinoJson/Operators/VariantOperators.hpp>
 #include <ArduinoJson/Polyfills/type_traits.hpp>
 #include <ArduinoJson/Variant/VariantAs.hpp>
 #include <ArduinoJson/Variant/VariantFunctions.hpp>
+#include <ArduinoJson/Variant/VariantOperators.hpp>
 #include <ArduinoJson/Variant/VariantRef.hpp>
+#include <ArduinoJson/Variant/VariantShortcuts.hpp>
 
 namespace ARDUINOJSON_NAMESPACE {
 
@@ -107,6 +108,9 @@ class VariantRefBase {
     return variantIsInteger<int>(_data);
   }
 
+  template <typename T>
+  int compare(const T &) const;  // VariantCompare.cpp
+
   FORCE_INLINE bool isNull() const {
     return variantIsNull(_data);
   }
@@ -141,6 +145,7 @@ class VariantRefBase {
 // - a reference to a ArrayRef or ObjectRef
 class VariantRef : public VariantRefBase<VariantData>,
                    public VariantOperators<VariantRef>,
+                   public VariantShortcuts<VariantRef>,
                    public Visitable {
   typedef VariantRefBase<VariantData> base_type;
   friend class VariantConstRef;
@@ -336,6 +341,7 @@ class VariantRef : public VariantRefBase<VariantData>,
 
 class VariantConstRef : public VariantRefBase<const VariantData>,
                         public VariantOperators<VariantConstRef>,
+                        public VariantShortcuts<VariantConstRef>,
                         public Visitable {
   typedef VariantRefBase<const VariantData> base_type;
   friend class VariantRef;

+ 0 - 0
src/ArduinoJson/Operators/VariantShortcuts.hpp → src/ArduinoJson/Variant/VariantShortcuts.hpp