diff --git a/src/json.hpp b/src/json.hpp index 4efe51f7..8e1186ae 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -8053,50 +8053,35 @@ class basic_json } } - /* - Use operator `const_iterator` instead of `const_iterator(const iterator& - other) noexcept` to avoid two class definitions for @ref iterator and - @ref const_iterator. - - This function is only called if this class is an @ref iterator. If this - class is a @ref const_iterator this function is not called. + /*! + @note The conventional copy constructor and copy assignment are + implicitly defined. + Combined with the following converting constructor and assigment, + they support: copy from iterator to iterator, + copy from const iterator to const iterator, + and conversion from iterator to const iterator. + However conversion from const iterator to iterator is not defined. */ - operator const_iterator() const - { - const_iterator ret; - - if (m_object) - { - ret.m_object = m_object; - ret.m_it = m_it; - } - - return ret; - } /*! - @brief copy constructor - @param[in] other iterator to copy from + @brief converting constructor + @param[in] other non-const iterator to copy from @note It is not checked whether @a other is initialized. */ - iter_impl(const iter_impl& other) noexcept + iter_impl(const iter_impl& other) noexcept : m_object(other.m_object), m_it(other.m_it) {} /*! - @brief copy assignment - @param[in,out] other iterator to copy from + @brief converting assignment + @param[in,out] other non-const iterator to copy from + @return const/non-const iterator @note It is not checked whether @a other is initialized. */ - iter_impl& operator=(iter_impl other) noexcept( - std::is_nothrow_move_constructible::value and - std::is_nothrow_move_assignable::value and - std::is_nothrow_move_constructible::value and - std::is_nothrow_move_assignable::value - ) + iter_impl& operator=(const iter_impl& other) noexcept { - std::swap(m_object, other.m_object); - std::swap(m_it, other.m_it); + m_object = other.m_object; + m_it = other.m_it; return *this; } @@ -8585,7 +8570,7 @@ class basic_json /// associated JSON instance pointer m_object = nullptr; /// the actual iterator of the associated instance - internal_iterator m_it = internal_iterator(); + struct internal_iterator m_it = internal_iterator(); }; /*! diff --git a/test/src/unit-iterators1.cpp b/test/src/unit-iterators1.cpp index 6605076a..2dc9aae8 100644 --- a/test/src/unit-iterators1.cpp +++ b/test/src/unit-iterators1.cpp @@ -1511,4 +1511,72 @@ TEST_CASE("iterators 1") } } } + + SECTION("conversion from iterator to const iterator") + { + SECTION("boolean") + { + json j = true; + json::const_iterator it = j.begin(); + CHECK(it == j.cbegin()); + it = j.begin(); + CHECK(it == j.cbegin()); + } + SECTION("string") + { + json j = "hello world"; + json::const_iterator it = j.begin(); + CHECK(it == j.cbegin()); + it = j.begin(); + CHECK(it == j.cbegin()); + } + SECTION("array") + { + json j = {1, 2, 3}; + json::const_iterator it = j.begin(); + CHECK(it == j.cbegin()); + it = j.begin(); + CHECK(it == j.cbegin()); + } + SECTION("object") + { + json j = {{"A", 1}, {"B", 2}, {"C", 3}}; + json::const_iterator it = j.begin(); + CHECK(it == j.cbegin()); + it = j.begin(); + CHECK(it == j.cbegin()); + } + SECTION("number (integer)") + { + json j = 23; + json::const_iterator it = j.begin(); + CHECK(it == j.cbegin()); + it = j.begin(); + CHECK(it == j.cbegin()); + } + SECTION("number (unsigned)") + { + json j = 23u; + json::const_iterator it = j.begin(); + CHECK(it == j.cbegin()); + it = j.begin(); + CHECK(it == j.cbegin()); + } + SECTION("number (float)") + { + json j = 23.42; + json::const_iterator it = j.begin(); + CHECK(it == j.cbegin()); + it = j.begin(); + CHECK(it == j.cbegin()); + } + SECTION("null") + { + json j = nullptr; + json::const_iterator it = j.begin(); + CHECK(it == j.cbegin()); + it = j.begin(); + CHECK(it == j.cbegin()); + } + } }