diff --git a/include/boost/json/impl/value.ipp b/include/boost/json/impl/value.ipp index b4e80f036..12d60f5ff 100644 --- a/include/boost/json/impl/value.ipp +++ b/include/boost/json/impl/value.ipp @@ -231,13 +231,28 @@ value( storage_ptr sp) { if(value_ref::maybe_object(init)) + { ::new(&obj_) object( value_ref::make_object( init, std::move(sp))); + } else - ::new(&arr_) array( - value_ref::make_array( - init, std::move(sp))); + { +#ifndef BOOST_JSON_LEGACY_INIT_LIST_BEHAVIOR + if( init.size() == 1 ) + { + ::new(&sca_) scalar(); + value temp = init.begin()->make_value( std::move(sp) ); + swap(temp); + } + else +#endif + { + ::new(&arr_) array( + value_ref::make_array( + init, std::move(sp))); + } + } } //---------------------------------------------------------- diff --git a/include/boost/json/value.hpp b/include/boost/json/value.hpp index 24df80a7e..a642acec6 100644 --- a/include/boost/json/value.hpp +++ b/include/boost/json/value.hpp @@ -1014,11 +1014,16 @@ class value /** Construct from an initializer-list - If the initializer list consists of key/value - pairs, an @ref object is created. Otherwise - an @ref array is created. The contents of the - initializer list are copied to the newly constructed - value using the specified memory resource. + @li If the initializer list consists of key/value + pairs, an @ref object is created; otherwise, + + @li if the size of the initializer list is exactly 1, the object is + constructed directly from that sole element; otherwise, + + @li an @ref array is created. + + The contents of the initializer list are copied to the newly + constructed value using the specified memory resource. @par Complexity Linear in `init.size()`. @@ -1032,6 +1037,20 @@ class value @param sp A pointer to the @ref memory_resource to use. The container will acquire shared ownership of the memory resource. + + @par Note + The previous behavior of this constructor was to always + construct either an @ref object or an @ref array. In practice though, + several C++ implementations did not treat `value{x}` as a constructor + from initializer list. This effectively resulted in different behavior + on different implementations.
+ + If you need the legacy behavior define macro + `BOOST_JSON_LEGACY_INIT_LIST_BEHAVIOR` when you are building the + library. The macro and the functionality will be deprecated in the + future and then removed, so we urge you to change your code for the new + behavior as soon as possible. The simplest way to create an @ref array + with 1 element using an initializer list is via `array{x}`. */ BOOST_JSON_DECL value( diff --git a/test/value.cpp b/test/value.cpp index 66ce1c6f7..315e77028 100644 --- a/test/value.cpp +++ b/test/value.cpp @@ -2131,6 +2131,17 @@ class value_test void testInitList() { + { + value jv{}; + BOOST_TEST( jv.is_null() ); + } +#ifndef BOOST_JSON_LEGACY_INIT_LIST_BEHAVIOR + { + value jv{0}; + BOOST_TEST( jv == 0 ); + } +#endif + check_array(value{0,0,0}, 0, 0, 0); check_array(value{false,false,false}, false, false, false); check_array(value{false,2,false}, false, 2, false);