Skip to content
Snippets Groups Projects
json.hpp 363 KiB
Newer Older

  @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
  object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
  @ref number_unsigned_t, or @ref number_float_t.

  @return pointer to the internally stored JSON value if the requested
  pointer type @a PointerType fits to the JSON value; `nullptr` otherwise

  @complexity Constant.

  @liveexample{The example below shows how pointers to internal values of a
  JSON value can be requested. Note that no type conversions are made and a
  `nullptr` is returned if the value and the requested pointer type does not
  match.,get__PointerType}

  @sa @ref get_ptr() for explicit pointer-member access

  @since version 1.0.0
  */
  template <typename PointerType,
            typename std::enable_if<std::is_pointer<PointerType>::value,
                                    int>::type = 0>
  PointerType get() noexcept
  {
    // delegate the call to get_ptr
    return get_ptr<PointerType>();
  }

  /*!
  @brief get a pointer value (explicit)
  @copydoc get()
  */
  template <typename PointerType,
            typename std::enable_if<std::is_pointer<PointerType>::value,
                                    int>::type = 0>
  constexpr const PointerType get() const noexcept
  {
    // delegate the call to get_ptr
    return get_ptr<PointerType>();
  }

  /*!
  @brief get a pointer value (implicit)

  Implicit pointer access to the internally stored JSON value. No copies are
  made.

  @warning Writing data to the pointee of the result yields an undefined
  state.

  @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
  object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
  @ref number_unsigned_t, or @ref number_float_t. Enforced by a static
  assertion.

  @return pointer to the internally stored JSON value if the requested
  pointer type @a PointerType fits to the JSON value; `nullptr` otherwise

  @complexity Constant.

  @liveexample{The example below shows how pointers to internal values of a
  JSON value can be requested. Note that no type conversions are made and a
  `nullptr` is returned if the value and the requested pointer type does not
  match.,get_ptr}

  @since version 1.0.0
  */
  template <typename PointerType,
            typename std::enable_if<std::is_pointer<PointerType>::value,
                                    int>::type = 0>
  PointerType get_ptr() noexcept
  {
    // get the type of the PointerType (remove pointer and const)
    using pointee_t = typename std::remove_const<typename std::remove_pointer<
        typename std::remove_const<PointerType>::type>::type>::type;
    // make sure the type matches the allowed types
    static_assert(std::is_same<object_t, pointee_t>::value or
                      std::is_same<array_t, pointee_t>::value or
                      std::is_same<string_t, pointee_t>::value or
                      std::is_same<boolean_t, pointee_t>::value or
                      std::is_same<number_integer_t, pointee_t>::value or
                      std::is_same<number_unsigned_t, pointee_t>::value or
                      std::is_same<number_float_t, pointee_t>::value,
                  "incompatible pointer type");

    // delegate the call to get_impl_ptr<>()
    return get_impl_ptr(static_cast<PointerType>(nullptr));
  }

  /*!
  @brief get a pointer value (implicit)
  @copydoc get_ptr()
  */
  template <
      typename PointerType,
      typename std::enable_if<std::is_pointer<PointerType>::value and
                                  std::is_const<typename std::remove_pointer<
                                      PointerType>::type>::value,
                              int>::type = 0>
  constexpr const PointerType get_ptr() const noexcept
  {
    // get the type of the PointerType (remove pointer and const)
    using pointee_t = typename std::remove_const<typename std::remove_pointer<
        typename std::remove_const<PointerType>::type>::type>::type;
    // make sure the type matches the allowed types
    static_assert(std::is_same<object_t, pointee_t>::value or
                      std::is_same<array_t, pointee_t>::value or
                      std::is_same<string_t, pointee_t>::value or
                      std::is_same<boolean_t, pointee_t>::value or
                      std::is_same<number_integer_t, pointee_t>::value or
                      std::is_same<number_unsigned_t, pointee_t>::value or
                      std::is_same<number_float_t, pointee_t>::value,
                  "incompatible pointer type");

    // delegate the call to get_impl_ptr<>() const
    return get_impl_ptr(static_cast<const PointerType>(nullptr));
  }

  /*!
  @brief get a reference value (implicit)

  Implict reference access to the internally stored JSON value. No copies
  are made.

  @warning Writing data to the referee of the result yields an undefined
  state.

  @tparam ReferenceType reference type; must be a reference to @ref array_t,
  @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or
  @ref number_float_t. Enforced by static assertion.

  @return reference to the internally stored JSON value if the requested
  reference type @a ReferenceType fits to the JSON value; throws
  std::domain_error otherwise

  @throw std::domain_error in case passed type @a ReferenceType is
  incompatible with the stored JSON value

  @complexity Constant.

  @liveexample{The example shows several calls to `get_ref()`.,get_ref}

  @since version 1.1.0
  */
  template <typename ReferenceType,
            typename std::enable_if<std::is_reference<ReferenceType>::value,
                                    int>::type = 0>
  ReferenceType get_ref()
  {
    // delegate call to get_ref_impl
    return get_ref_impl<ReferenceType>(*this);
  }

  /*!
  @brief get a reference value (implicit)
  @copydoc get_ref()
  */
  template <
      typename ReferenceType,
      typename std::enable_if<std::is_reference<ReferenceType>::value and
                                  std::is_const<typename std::remove_reference<
                                      ReferenceType>::type>::value,
                              int>::type = 0>
  ReferenceType get_ref() const
  {
    // delegate call to get_ref_impl
    return get_ref_impl<ReferenceType>(*this);
  }

  /*!
  @brief get a value (implicit)

  Implicit type conversion between the JSON value and a compatible value.
  The call is realized by calling @ref get() const.

  @tparam ValueType non-pointer type compatible to the JSON value, for
  instance `int` for JSON integer numbers, `bool` for JSON booleans, or
  `std::vector` types for JSON arrays. The character type of @ref string_t
  as well as an initializer list of this type is excluded to avoid
  ambiguities as these types implicitly convert to `std::string`.

  @return copy of the JSON value, converted to type @a ValueType

  @throw std::domain_error in case passed type @a ValueType is incompatible
  to JSON, thrown by @ref get() const

  @complexity Linear in the size of the JSON value.

  @liveexample{The example below shows several conversions from JSON values
  to other types. There a few things to note: (1) Floating-point numbers can
  be converted to integers\, (2) A JSON array can be converted to a standard
  `std::vector<short>`\, (3) A JSON object can be converted to C++
  associative containers such as `std::unordered_map<std::string\,
  json>`.,operator__ValueType}

  @since version 1.0.0
  */
  template <
      typename ValueType,
      typename std::enable_if<
          not std::is_pointer<ValueType>::value and
              not std::is_same<ValueType, typename string_t::value_type>::value
#ifndef _MSC_VER // fix for issue #167 operator<< abiguity under VS2015
              and
              not std::is_same<
                  ValueType,
                  std::initializer_list<typename string_t::value_type>>::value
#endif
          ,
          int>::type = 0>
  operator ValueType() const
  {
    // delegate the call to get<>() const
    return get<ValueType>();
  }
  ////////////////////
  // element access //
  ////////////////////
  /// @name element access
  /// Access to the JSON value.
  /// @{
  /*!
  @brief access specified array element with bounds checking
  Returns a reference to the element at specified location @a idx, with
  bounds checking.
  @param[in] idx  index of the element to access
  @return reference to the element at index @a idx
  @throw std::domain_error if the JSON value is not an array; example:
  `"cannot use at() with string"`
  @throw std::out_of_range if the index @a idx is out of range of the array;
  that is, `idx >= size()`; example: `"array index 7 is out of range"`
  @complexity Constant.

  @liveexample{The example below shows how array elements can be read and
  written using `at()`.,at__size_type}

  @since version 1.0.0
  */
  reference at(size_type idx)
  {
    // at only works for arrays
    if (is_array())
      JSON_TRY { return m_value.array->at(idx); }
      JSON_CATCH(std::out_of_range &)
      {
        // create better exception explanation
        JSON_THROW(std::out_of_range("array index " + std::to_string(idx) +
                                     " is out of range"));
      }
    else
    {
      JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
    }
  }
  /*!
  @brief access specified array element with bounds checking
  Returns a const reference to the element at specified location @a idx,
  with bounds checking.
  @param[in] idx  index of the element to access
  @return const reference to the element at index @a idx
  @throw std::domain_error if the JSON value is not an array; example:
  `"cannot use at() with string"`
  @throw std::out_of_range if the index @a idx is out of range of the array;
  that is, `idx >= size()`; example: `"array index 7 is out of range"`
  @complexity Constant.
  @liveexample{The example below shows how array elements can be read using
  `at()`.,at__size_type_const}
  @since version 1.0.0
  */
  const_reference at(size_type idx) const
  {
    // at only works for arrays
    if (is_array())
    {
      JSON_TRY { return m_value.array->at(idx); }
      JSON_CATCH(std::out_of_range &)
      {
        // create better exception explanation
        JSON_THROW(std::out_of_range("array index " + std::to_string(idx) +
                                     " is out of range"));
      }
    }
    else
      JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
    }
  }
  /*!
  @brief access specified object element with bounds checking
  Returns a reference to the element at with specified key @a key, with
  bounds checking.
  @param[in] key  key of the element to access
  @return reference to the element at key @a key
  @throw std::domain_error if the JSON value is not an object; example:
  `"cannot use at() with boolean"`
  @throw std::out_of_range if the key @a key is is not stored in the object;
  that is, `find(key) == end()`; example: `"key "the fast" not found"`
  @complexity Logarithmic in the size of the container.
  @liveexample{The example below shows how object elements can be read and
  written using `at()`.,at__object_t_key_type}
  @sa @ref operator[](const typename object_t::key_type&) for unchecked
  access by reference
  @sa @ref value() for access by value with a default value
  @since version 1.0.0
  */
  reference at(const typename object_t::key_type &key)
  {
    // at only works for objects
    if (is_object())
    {
      JSON_TRY { return m_value.object->at(key); }
      JSON_CATCH(std::out_of_range &)
      {
        // create better exception explanation
        JSON_THROW(std::out_of_range("key '" + key + "' not found"));
      }
    else
    {
      JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
    }
  }
  /*!
  @brief access specified object element with bounds checking
  Returns a const reference to the element at with specified key @a key,
  with bounds checking.
  @param[in] key  key of the element to access
  @return const reference to the element at key @a key
  @throw std::domain_error if the JSON value is not an object; example:
  `"cannot use at() with boolean"`
  @throw std::out_of_range if the key @a key is is not stored in the object;
  that is, `find(key) == end()`; example: `"key "the fast" not found"`
  @complexity Logarithmic in the size of the container.
  @liveexample{The example below shows how object elements can be read using
  `at()`.,at__object_t_key_type_const}
  @sa @ref operator[](const typename object_t::key_type&) for unchecked
  access by reference
  @sa @ref value() for access by value with a default value
  @since version 1.0.0
  */
  const_reference at(const typename object_t::key_type &key) const
  {
    // at only works for objects
    if (is_object())
    {
      JSON_TRY { return m_value.object->at(key); }
      JSON_CATCH(std::out_of_range &)
      {
        // create better exception explanation
        JSON_THROW(std::out_of_range("key '" + key + "' not found"));
      }
    else
    {
      JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
    }
  }
  /*!
  @brief access specified array element
  Returns a reference to the element at specified location @a idx.
  @note If @a idx is beyond the range of the array (i.e., `idx >= size()`),
  then the array is silently filled up with `null` values to make `idx` a
  valid reference to the last stored element.
  @param[in] idx  index of the element to access
  @return reference to the element at index @a idx
  @throw std::domain_error if JSON is not an array or null; example:
  `"cannot use operator[] with string"`
  @complexity Constant if @a idx is in the range of the array. Otherwise
  linear in `idx - size()`.

  @liveexample{The example below shows how array elements can be read and
  written using `[]` operator. Note the addition of `null`
  values.,operatorarray__size_type}

  @since version 1.0.0
  */
  reference operator[](size_type idx)
  {
    // implicitly convert null value to an empty array
    if (is_null())
      m_type = value_t::array;
      m_value.array = create<array_t>();
      assert_invariant();
    }
    // operator[] only works for arrays
    if (is_array())
    {
      // fill up array with null values if given idx is outside range
      if (idx >= m_value.array->size())
      {
        m_value.array->insert(m_value.array->end(),
                              idx - m_value.array->size() + 1, basic_json());
      }
      return m_value.array->operator[](idx);
    JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
  }
  /*!
  @brief access specified array element
  Returns a const reference to the element at specified location @a idx.
  @param[in] idx  index of the element to access
  @return const reference to the element at index @a idx
  @throw std::domain_error if JSON is not an array; example: `"cannot use
  operator[] with null"`
  @complexity Constant.
  @liveexample{The example below shows how array elements can be read using
  the `[]` operator.,operatorarray__size_type_const}
  @since version 1.0.0
  */
  const_reference operator[](size_type idx) const
  {
    // const operator[] only works for arrays
    if (is_array())
    {
      return m_value.array->operator[](idx);
    JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
  }
  /*!
  @brief access specified object element
  Returns a reference to the element at with specified key @a key.
  @note If @a key is not found in the object, then it is silently added to
  the object and filled with a `null` value to make `key` a valid reference.
  In case the value was `null` before, it is converted to an object.
  @param[in] key  key of the element to access
  @return reference to the element at key @a key
  @throw std::domain_error if JSON is not an object or null; example:
  `"cannot use operator[] with string"`
  @complexity Logarithmic in the size of the container.
  @liveexample{The example below shows how object elements can be read and
  written using the `[]` operator.,operatorarray__key_type}
  @sa @ref at(const typename object_t::key_type&) for access by reference
  with range checking
  @sa @ref value() for access by value with a default value
  @since version 1.0.0
  */
  reference operator[](const typename object_t::key_type &key)
  {
    // implicitly convert null value to an empty object
    if (is_null())
      m_type = value_t::object;
      m_value.object = create<object_t>();
      assert_invariant();
    }
    // operator[] only works for objects
    if (is_object())
    {
      return m_value.object->operator[](key);
    JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
  }
  /*!
  @brief read-only access specified object element
  Returns a const reference to the element at with specified key @a key. No
  bounds checking is performed.
  @warning If the element with key @a key does not exist, the behavior is
  undefined.
  @param[in] key  key of the element to access
  @return const reference to the element at key @a key
  @pre The element with key @a key must exist. **This precondition is
       enforced with an assertion.**
  @throw std::domain_error if JSON is not an object; example: `"cannot use
  operator[] with null"`
  @complexity Logarithmic in the size of the container.
  @liveexample{The example below shows how object elements can be read using
  the `[]` operator.,operatorarray__key_type_const}
  @sa @ref at(const typename object_t::key_type&) for access by reference
  with range checking
  @sa @ref value() for access by value with a default value
  @since version 1.0.0
  */
  const_reference operator[](const typename object_t::key_type &key) const
  {
    // const operator[] only works for objects
    if (is_object())
    {
      assert(m_value.object->find(key) != m_value.object->end());
      return m_value.object->find(key)->second;
    }
    JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
  }
  /*!
  @brief access specified object element
  Returns a reference to the element at with specified key @a key.
  @note If @a key is not found in the object, then it is silently added to
  the object and filled with a `null` value to make `key` a valid reference.
  In case the value was `null` before, it is converted to an object.
  @param[in] key  key of the element to access
  @return reference to the element at key @a key
  @throw std::domain_error if JSON is not an object or null; example:
  `"cannot use operator[] with string"`
  @complexity Logarithmic in the size of the container.
  @liveexample{The example below shows how object elements can be read and
  written using the `[]` operator.,operatorarray__key_type}
  @sa @ref at(const typename object_t::key_type&) for access by reference
  with range checking
  @sa @ref value() for access by value with a default value
  @since version 1.0.0
  */
  template <typename T, std::size_t n> reference operator[](T *(&key)[n])
  {
    return operator[](static_cast<const T>(key));
  }
  /*!
  @brief read-only access specified object element
  Returns a const reference to the element at with specified key @a key. No
  bounds checking is performed.
  @warning If the element with key @a key does not exist, the behavior is
  undefined.
  @note This function is required for compatibility reasons with Clang.
  @param[in] key  key of the element to access
  @return const reference to the element at key @a key
  @throw std::domain_error if JSON is not an object; example: `"cannot use
  operator[] with null"`
  @complexity Logarithmic in the size of the container.
  @liveexample{The example below shows how object elements can be read using
  the `[]` operator.,operatorarray__key_type_const}
  @sa @ref at(const typename object_t::key_type&) for access by reference
  with range checking
  @sa @ref value() for access by value with a default value
  @since version 1.0.0
  */
  template <typename T, std::size_t n>
  const_reference operator[](T *(&key)[n]) const
  {
    return operator[](static_cast<const T>(key));
  }
  /*!
  @brief access specified object element
  Returns a reference to the element at with specified key @a key.
  @note If @a key is not found in the object, then it is silently added to
  the object and filled with a `null` value to make `key` a valid reference.
  In case the value was `null` before, it is converted to an object.
  @param[in] key  key of the element to access
  @return reference to the element at key @a key
  @throw std::domain_error if JSON is not an object or null; example:
  `"cannot use operator[] with string"`
  @complexity Logarithmic in the size of the container.
  @liveexample{The example below shows how object elements can be read and
  written using the `[]` operator.,operatorarray__key_type}
  @sa @ref at(const typename object_t::key_type&) for access by reference
  with range checking
  @sa @ref value() for access by value with a default value
  @since version 1.1.0
  */
  template <typename T> reference operator[](T *key)
  {
    // implicitly convert null to object
    if (is_null())
    {
      m_type = value_t::object;
      m_value = value_t::object;
      assert_invariant();
    }
    // at only works for objects
    if (is_object())
      return m_value.object->operator[](key);
    JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
  }
  /*!
  @brief read-only access specified object element
  Returns a const reference to the element at with specified key @a key. No
  bounds checking is performed.
  @warning If the element with key @a key does not exist, the behavior is
  undefined.
  @param[in] key  key of the element to access
  @return const reference to the element at key @a key
  @pre The element with key @a key must exist. **This precondition is
       enforced with an assertion.**
  @throw std::domain_error if JSON is not an object; example: `"cannot use
  operator[] with null"`

  @complexity Logarithmic in the size of the container.

  @liveexample{The example below shows how object elements can be read using
  the `[]` operator.,operatorarray__key_type_const}

  @sa @ref at(const typename object_t::key_type&) for access by reference
  with range checking
  @sa @ref value() for access by value with a default value

  @since version 1.1.0
  */
  template <typename T> const_reference operator[](T *key) const
  {
    // at only works for objects
    if (is_object())
      assert(m_value.object->find(key) != m_value.object->end());
      return m_value.object->find(key)->second;
    JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
  }
  /*!
  @brief access specified object element with default value
  Returns either a copy of an object's element at the specified key @a key
  or a given default value if no element with key @a key exists.
  The function is basically equivalent to executing
  @code {.cpp}
  try {
      return at(key);
  } catch(std::out_of_range) {
      return default_value;
  }
  @endcode
  @note Unlike @ref at(const typename object_t::key_type&), this function
  does not throw if the given key @a key was not found.
  @note Unlike @ref operator[](const typename object_t::key_type& key), this
  function does not implicitly add an element to the position defined by @a
  key. This function is furthermore also applicable to const objects.
  @param[in] key  key of the element to access
  @param[in] default_value  the value to return if @a key is not found
  @tparam ValueType type compatible to JSON values, for instance `int` for
  JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for
  JSON arrays. Note the type of the expected value at @a key and the default
  value @a default_value must be compatible.
  @return copy of the element at key @a key or @a default_value if @a key
  is not found
  @throw std::domain_error if JSON is not an object; example: `"cannot use
  value() with null"`
  @complexity Logarithmic in the size of the container.
  @liveexample{The example below shows how object elements can be queried
  with a default value.,basic_json__value}
  @sa @ref at(const typename object_t::key_type&) for access by reference
  with range checking
  @sa @ref operator[](const typename object_t::key_type&) for unchecked
  access by reference
  @since version 1.0.0
  */
  template <
      class ValueType,
      typename std::enable_if<
          std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
  ValueType value(const typename object_t::key_type &key,
                  ValueType default_value) const
  {
    // at only works for objects
    if (is_object())
    {
      // if key is found, return value and given default value otherwise
      const auto it = find(key);
      if (it != end())
      {
        return *it;
      }
      return default_value;
    }
    else
      JSON_THROW(std::domain_error("cannot use value() with " + type_name()));
  /*!
  @brief overload for a default value of type const char*
  @copydoc basic_json::value(const typename object_t::key_type&, ValueType)
  const
  */
  string_t value(const typename object_t::key_type &key,
                 const char *default_value) const
  {
    return value(key, string_t(default_value));
  }
  /*!
  @brief access specified object element via JSON Pointer with default value
  Returns either a copy of an object's element at the specified key @a key
  or a given default value if no element with key @a key exists.
  The function is basically equivalent to executing
  @code {.cpp}
  try {
      return at(ptr);
  } catch(std::out_of_range) {
      return default_value;
  }
  @endcode

  @note Unlike @ref at(const json_pointer&), this function does not throw
  if the given key @a key was not found.

  @param[in] ptr  a JSON pointer to the element to access
  @param[in] default_value  the value to return if @a ptr found no value

  @tparam ValueType type compatible to JSON values, for instance `int` for
  JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for
  JSON arrays. Note the type of the expected value at @a key and the default
  value @a default_value must be compatible.
  @return copy of the element at key @a key or @a default_value if @a key
  is not found
  @throw std::domain_error if JSON is not an object; example: `"cannot use
  value() with null"`
  @complexity Logarithmic in the size of the container.

  @liveexample{The example below shows how object elements can be queried
  with a default value.,basic_json__value_ptr}

  @sa @ref operator[](const json_pointer&) for unchecked access by reference

  @since version 2.0.2
  */
  template <
      class ValueType,
      typename std::enable_if<
          std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
  ValueType value(const json_pointer &ptr, ValueType default_value) const
  {
    // at only works for objects
    if (is_object())
      // if pointer resolves a value, return it or use default value
      JSON_TRY { return ptr.get_checked(this); }
      JSON_CATCH(std::out_of_range &) { return default_value; }
    JSON_THROW(std::domain_error("cannot use value() with " + type_name()));
  }

  /*!
  @brief overload for a default value of type const char*
  @copydoc basic_json::value(const json_pointer&, ValueType) const
  */
  string_t value(const json_pointer &ptr, const char *default_value) const
  {
    return value(ptr, string_t(default_value));
  }

  /*!
  @brief access the first element
  Returns a reference to the first element in the container. For a JSON
  container `c`, the expression `c.front()` is equivalent to `*c.begin()`.
  @return In case of a structured type (array or object), a reference to the
  first element is returned. In case of number, string, or boolean values, a
  reference to the value is returned.
  @complexity Constant.
  @pre The JSON value must not be `null` (would throw `std::out_of_range`)
  or an empty array or object (undefined behavior, **guarded by
  assertions**).
  @post The JSON value remains unchanged.
  @throw std::out_of_range when called on `null` value
  @liveexample{The following code shows an example for `front()`.,front}
  @sa @ref back() -- access the last element
  @since version 1.0.0
  */
  reference front() { return *begin(); }
  /*!
  @copydoc basic_json::front()
  */
  const_reference front() const { return *cbegin(); }
  /*!
  @brief access the last element
  Returns a reference to the last element in the container. For a JSON
  container `c`, the expression `c.back()` is equivalent to
  @code {.cpp}
  auto tmp = c.end();
  --tmp;
  return *tmp;
  @endcode
  @return In case of a structured type (array or object), a reference to the
  last element is returned. In case of number, string, or boolean values, a
  reference to the value is returned.
  @complexity Constant.
  @pre The JSON value must not be `null` (would throw `std::out_of_range`)
  or an empty array or object (undefined behavior, **guarded by
  assertions**).
  @post The JSON value remains unchanged.
  @throw std::out_of_range when called on `null` value.
  @liveexample{The following code shows an example for `back()`.,back}
  @sa @ref front() -- access the first element
  @since version 1.0.0
  */
  reference back()
  {
    auto tmp = end();
    --tmp;
    return *tmp;
  }

  /*!
  @copydoc basic_json::back()
  */
  const_reference back() const
  {
    auto tmp = cend();
    --tmp;
    return *tmp;
  }
  /*!
  @brief remove element given an iterator
  Removes the element specified by iterator @a pos. The iterator @a pos must
  be valid and dereferenceable. Thus the `end()` iterator (which is valid,
  but is not dereferenceable) cannot be used as a value for @a pos.
  If called on a primitive type other than `null`, the resulting JSON value
  will be `null`.
  @param[in] pos iterator to the element to remove
  @return Iterator following the last removed element. If the iterator @a
  pos refers to the last element, the `end()` iterator is returned.
  @tparam IteratorType an @ref iterator or @ref const_iterator
  @post Invalidates iterators and references at or after the point of the
  erase, including the `end()` iterator.
  @throw std::domain_error if called on a `null` value; example: `"cannot
  use erase() with null"`
  @throw std::domain_error if called on an iterator which does not belong to
  the current JSON value; example: `"iterator does not fit current value"`
  @throw std::out_of_range if called on a primitive type with invalid
  iterator (i.e., any iterator which is not `begin()`); example: `"iterator
  out of range"`
  @complexity The complexity depends on the type:
  - objects: amortized constant
  - arrays: linear in distance between pos and the end of the container
  - strings: linear in the length of the string
  - other types: constant
  @liveexample{The example shows the result of `erase()` for different JSON
  types.,erase__IteratorType}
  @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
  the given range
  @sa @ref erase(const typename object_t::key_type&) -- removes the element
  from an object at the given key
  @sa @ref erase(const size_type) -- removes the element from an array at
  the given index

  @since version 1.0.0
  */
  template <
      class IteratorType,
      typename std::enable_if<
          std::is_same<IteratorType, typename basic_json_t::iterator>::value or
              std::is_same<IteratorType,