When the subject of a future is a type which defines an initializer list constructor and can be compounded recursively, i.e. json, the code ends up incorrectly passing the object as an rvalue to the intializer list constructor instead of the rvalue& ctor.
E.g. a json object returned as {"a":1} would go through the transformations:
// 1. create and return the future holding the object
...
json obj;
obj["a"] = 1;
return make_ready_future<json>(std::move(obj));
// 2. class uninitialized_wrapper_base::uninitialized_set would be invoked to set the value of the promise:
uninitialized_set(U&&... vs) {
new (&_v.value) maybe_wrap_ref<T>{T(std::forward<U>(vs)...)};
// ^ unneeded temporary passed to initializer list ctor
}
// 3. we now not only created a temporary json object which is not needed, but also passed it as an
// rvalue to the initializer list constructor
json::json(std::initializer_list<T> il);
// 4. json now thinks we want to embed a json object inside a new json object, and since it is a single
// element, the only way it can do so is as an array:
// result is now: [{"a":1}]
When the subject of a future is a type which defines an initializer list constructor and can be compounded recursively, i.e. json, the code ends up incorrectly passing the object as an rvalue to the intializer list constructor instead of the rvalue& ctor.
E.g. a json object returned as {"a":1} would go through the transformations: