diff --git a/src/json.hpp b/src/json.hpp
index a9da694c..af8e490d 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -587,6 +587,95 @@ class basic_json
         alloc.construct(m_value.array, count, other);
     }
 
+    // construct a JSON container given an iterator range
+    template <class T, typename
+              std::enable_if<
+                  std::is_same<T, basic_json::iterator>::value or
+                  std::is_same<T, basic_json::const_iterator>::value
+                  , int>::type
+              = 0>
+    inline basic_json(T first, T last)
+    {
+        // make sure iterator fits the current value
+        if (first.m_object != last.m_object or
+                first.m_object->m_type != last.m_object->m_type)
+        {
+            throw std::runtime_error("iterators are not compatible");
+        }
+
+        m_type = first.m_object->m_type;
+
+        switch (m_type)
+        {
+            case value_t::number_integer:
+            case value_t::number_float:
+            case value_t::boolean:
+            case value_t::string:
+            {
+                if (first.m_it.generic_iterator != 0 or last.m_it.generic_iterator != 1)
+                {
+                    throw std::out_of_range("iterators out of range");
+                }
+                break;
+            }
+
+            default:
+            {
+                break;
+            }
+        }
+
+        switch (m_type)
+        {
+            case value_t::number_integer:
+            {
+                m_value.number_integer = first.m_object->m_value.number_integer;
+                break;
+            }
+
+            case value_t::number_float:
+            {
+                m_value.number_float = first.m_object->m_value.number_float;
+                break;
+            }
+
+            case value_t::boolean:
+            {
+                m_value.boolean = first.m_object->m_value.boolean;
+                break;
+            }
+
+            case value_t::string:
+            {
+                AllocatorType<string_t> alloc;
+                m_value.string = alloc.allocate(1);
+                alloc.construct(m_value.string, *first.m_object->m_value.string);
+                break;
+            }
+
+            case value_t::object:
+            {
+                AllocatorType<object_t> alloc;
+                m_value.object = alloc.allocate(1);
+                alloc.construct(m_value.object, first.m_it.object_iterator, last.m_it.object_iterator);
+                break;
+            }
+
+            case value_t::array:
+            {
+                AllocatorType<array_t> alloc;
+                m_value.array = alloc.allocate(1);
+                alloc.construct(m_value.array, first.m_it.array_iterator, last.m_it.array_iterator);
+                break;
+            }
+
+            default:
+            {
+                throw std::runtime_error("cannot use construct with iterators from " + first.m_object->type_name());
+            }
+        }
+    }
+
     ///////////////////////////////////////
     // other constructors and destructor //
     ///////////////////////////////////////
diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c
index 58d80d9d..2ad9924c 100644
--- a/src/json.hpp.re2c
+++ b/src/json.hpp.re2c
@@ -587,6 +587,97 @@ class basic_json
         alloc.construct(m_value.array, count, other);
     }
 
+    /// construct a JSON container given an iterator range
+    template <class T, typename
+              std::enable_if<
+                  std::is_same<T, basic_json::iterator>::value or
+                  std::is_same<T, basic_json::const_iterator>::value
+                  , int>::type
+              = 0>
+    inline basic_json(T first, T last)
+    {
+        // make sure iterator fits the current value
+        if (first.m_object != last.m_object or
+                first.m_object->m_type != last.m_object->m_type)
+        {
+            throw std::runtime_error("iterators are not compatible");
+        }
+
+        // set the type
+        m_type = first.m_object->m_type;
+
+        // check if iterator range is complete for non-compound values
+        switch (m_type)
+        {
+            case value_t::number_integer:
+            case value_t::number_float:
+            case value_t::boolean:
+            case value_t::string:
+            {
+                if (first.m_it.generic_iterator != 0 or last.m_it.generic_iterator != 1)
+                {
+                    throw std::out_of_range("iterators out of range");
+                }
+                break;
+            }
+
+            default:
+            {
+                break;
+            }
+        }
+
+        switch (m_type)
+        {
+            case value_t::number_integer:
+            {
+                m_value.number_integer = first.m_object->m_value.number_integer;
+                break;
+            }
+
+            case value_t::number_float:
+            {
+                m_value.number_float = first.m_object->m_value.number_float;
+                break;
+            }
+
+            case value_t::boolean:
+            {
+                m_value.boolean = first.m_object->m_value.boolean;
+                break;
+            }
+
+            case value_t::string:
+            {
+                AllocatorType<string_t> alloc;
+                m_value.string = alloc.allocate(1);
+                alloc.construct(m_value.string, *first.m_object->m_value.string);
+                break;
+            }
+
+            case value_t::object:
+            {
+                AllocatorType<object_t> alloc;
+                m_value.object = alloc.allocate(1);
+                alloc.construct(m_value.object, first.m_it.object_iterator, last.m_it.object_iterator);
+                break;
+            }
+
+            case value_t::array:
+            {
+                AllocatorType<array_t> alloc;
+                m_value.array = alloc.allocate(1);
+                alloc.construct(m_value.array, first.m_it.array_iterator, last.m_it.array_iterator);
+                break;
+            }
+
+            default:
+            {
+                throw std::runtime_error("cannot use construct with iterators from " + first.m_object->type_name());
+            }
+        }
+    }
+
     ///////////////////////////////////////
     // other constructors and destructor //
     ///////////////////////////////////////
diff --git a/test/unit.cpp b/test/unit.cpp
index e251f776..fe6a31b0 100644
--- a/test/unit.cpp
+++ b/test/unit.cpp
@@ -913,6 +913,257 @@ TEST_CASE("constructors")
             CHECK(x == v);
         }
     }
+
+    SECTION("create a JSON container from an iterator range")
+    {
+        SECTION("object")
+        {
+            SECTION("json(begin(), end())")
+            {
+                {
+                    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}};
+                    json j_new(jobject.begin(), jobject.end());
+                    CHECK(j_new == jobject);
+                }
+                {
+                    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}};
+                    json j_new(jobject.cbegin(), jobject.cend());
+                    CHECK(j_new == jobject);
+                }
+            }
+
+            SECTION("json(begin(), begin())")
+            {
+                {
+                    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}};
+                    json j_new(jobject.begin(), jobject.begin());
+                    CHECK(j_new == json::object());
+                }
+                {
+                    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}};
+                    json j_new(jobject.cbegin(), jobject.cbegin());
+                    CHECK(j_new == json::object());
+                }
+            }
+
+            SECTION("construct from subrange")
+            {
+                json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}, {"d", false}, {"e", true}};
+                json j_new(jobject.find("b"), jobject.find("e"));
+                CHECK(j_new == json({{"b", 1}, {"c", 17}, {"d", false}}));
+            }
+
+            SECTION("incompatible iterators")
+            {
+                {
+                    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}, {"d", false}, {"e", true}};
+                    json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17}};
+                    CHECK_THROWS_AS(json(jobject.begin(), jobject2.end()), std::runtime_error);
+                    CHECK_THROWS_AS(json(jobject2.begin(), jobject.end()), std::runtime_error);
+                }
+                {
+                    json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}, {"d", false}, {"e", true}};
+                    json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17}};
+                    CHECK_THROWS_AS(json(jobject.cbegin(), jobject2.cend()), std::runtime_error);
+                    CHECK_THROWS_AS(json(jobject2.cbegin(), jobject.cend()), std::runtime_error);
+                }
+            }
+        }
+
+        SECTION("array")
+        {
+            SECTION("json(begin(), end())")
+            {
+                {
+                    json jarray = {1, 2, 3, 4, 5};
+                    json j_new(jarray.begin(), jarray.end());
+                    CHECK(j_new == jarray);
+                }
+                {
+                    json jarray = {1, 2, 3, 4, 5};
+                    json j_new(jarray.cbegin(), jarray.cend());
+                    CHECK(j_new == jarray);
+                }
+            }
+
+            SECTION("json(begin(), begin())")
+            {
+                {
+                    json jarray = {1, 2, 3, 4, 5};
+                    json j_new(jarray.begin(), jarray.begin());
+                    CHECK(j_new == json::array());
+                }
+                {
+                    json jarray = {1, 2, 3, 4, 5};
+                    json j_new(jarray.cbegin(), jarray.cbegin());
+                    CHECK(j_new == json::array());
+                }
+            }
+
+            SECTION("construct from subrange")
+            {
+                {
+                    json jarray = {1, 2, 3, 4, 5};
+                    json j_new(jarray.begin() + 1, jarray.begin() + 3);
+                    CHECK(j_new == json({2, 3}));
+                }
+                {
+                    json jarray = {1, 2, 3, 4, 5};
+                    json j_new(jarray.cbegin() + 1, jarray.cbegin() + 3);
+                    CHECK(j_new == json({2, 3}));
+                }
+            }
+
+            SECTION("incompatible iterators")
+            {
+                {
+                    json jarray = {1, 2, 3, 4};
+                    json jarray2 = {2, 3, 4, 5};
+                    CHECK_THROWS_AS(json(jarray.begin(), jarray2.end()), std::runtime_error);
+                    CHECK_THROWS_AS(json(jarray2.begin(), jarray.end()), std::runtime_error);
+                }
+                {
+                    json jarray = {1, 2, 3, 4};
+                    json jarray2 = {2, 3, 4, 5};
+                    CHECK_THROWS_AS(json(jarray.cbegin(), jarray2.cend()), std::runtime_error);
+                    CHECK_THROWS_AS(json(jarray2.cbegin(), jarray.cend()), std::runtime_error);
+                }
+            }
+        }
+
+        SECTION("other values")
+        {
+            SECTION("construct with two valid iterators")
+            {
+                SECTION("null")
+                {
+                    {
+                        json j;
+                        CHECK_THROWS_AS(json(j.begin(), j.end()), std::runtime_error);
+                    }
+                    {
+                        json j;
+                        CHECK_THROWS_AS(json(j.cbegin(), j.cend()), std::runtime_error);
+                    }
+                }
+
+                SECTION("string")
+                {
+                    {
+                        json j = "foo";
+                        json j_new(j.begin(), j.end());
+                        CHECK(j == j_new);
+                    }
+                    {
+                        json j = "bar";
+                        json j_new(j.cbegin(), j.cend());
+                        CHECK(j == j_new);
+                    }
+                }
+
+                SECTION("number (boolean)")
+                {
+                    {
+                        json j = false;
+                        json j_new(j.begin(), j.end());
+                        CHECK(j == j_new);
+                    }
+                    {
+                        json j = true;
+                        json j_new(j.cbegin(), j.cend());
+                        CHECK(j == j_new);
+                    }
+                }
+
+                SECTION("number (integer)")
+                {
+                    {
+                        json j = 17;
+                        json j_new(j.begin(), j.end());
+                        CHECK(j == j_new);
+                    }
+                    {
+                        json j = 17;
+                        json j_new(j.cbegin(), j.cend());
+                        CHECK(j == j_new);
+                    }
+                }
+
+                SECTION("number (floating point)")
+                {
+                    {
+                        json j = 23.42;
+                        json j_new(j.begin(), j.end());
+                        CHECK(j == j_new);
+                    }
+                    {
+                        json j = 23.42;
+                        json j_new(j.cbegin(), j.cend());
+                        CHECK(j == j_new);
+                    }
+                }
+            }
+
+            SECTION("construct with two invalid iterators")
+            {
+                SECTION("string")
+                {
+                    {
+                        json j = "foo";
+                        CHECK_THROWS_AS(json(j.end(), j.end()), std::out_of_range);
+                        CHECK_THROWS_AS(json(j.begin(), j.begin()), std::out_of_range);
+                    }
+                    {
+                        json j = "bar";
+                        CHECK_THROWS_AS(json(j.cend(), j.cend()), std::out_of_range);
+                        CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), std::out_of_range);
+                    }
+                }
+
+                SECTION("number (boolean)")
+                {
+                    {
+                        json j = false;
+                        CHECK_THROWS_AS(json(j.end(), j.end()), std::out_of_range);
+                        CHECK_THROWS_AS(json(j.begin(), j.begin()), std::out_of_range);
+                    }
+                    {
+                        json j = true;
+                        CHECK_THROWS_AS(json(j.cend(), j.cend()), std::out_of_range);
+                        CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), std::out_of_range);
+                    }
+                }
+
+                SECTION("number (integer)")
+                {
+                    {
+                        json j = 17;
+                        CHECK_THROWS_AS(json(j.end(), j.end()), std::out_of_range);
+                        CHECK_THROWS_AS(json(j.begin(), j.begin()), std::out_of_range);
+                    }
+                    {
+                        json j = 17;
+                        CHECK_THROWS_AS(json(j.cend(), j.cend()), std::out_of_range);
+                        CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), std::out_of_range);
+                    }
+                }
+
+                SECTION("number (floating point)")
+                {
+                    {
+                        json j = 23.42;
+                        CHECK_THROWS_AS(json(j.end(), j.end()), std::out_of_range);
+                        CHECK_THROWS_AS(json(j.begin(), j.begin()), std::out_of_range);
+                    }
+                    {
+                        json j = 23.42;
+                        CHECK_THROWS_AS(json(j.cend(), j.cend()), std::out_of_range);
+                        CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), std::out_of_range);
+                    }
+                }
+            }
+        }
+    }
 }
 
 TEST_CASE("other constructors and destructor")
@@ -2807,7 +3058,7 @@ TEST_CASE("element access")
                     }
                 }
 
-                SECTION("different arrays")
+                SECTION("different objects")
                 {
                     {
                         json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}, {"d", false}, {"e", true}};