nlohmann / json

JSON for Modern C++
https://json.nlohmann.me
MIT License
41.3k stars 6.58k forks source link

Inconsistent behaviour of json construction using `std::initializer_list` #4299

Closed aarlt closed 4 months ago

aarlt commented 4 months ago

Description

The construction of a json object using an initializer_list that defines a single element is creating an array for strings and other basic types. This behaviour is different from the usage of other (json) types.

Reproduction steps

See example.

Expected vs. actual results

I would expect that the usage of an intitializer_list would either always create an array, e.g.

{}
[{}]
{}
"hello"
["hello"]
"hello"
[]
[[]]
[]

Or never (from my point of view the correct behaviour, if only a single element was defined):

{}
{}
{}
"hello"
"hello"
"hello"
[]
[]
[]

Minimal code example

int main(int, char*[])
{
  nlohmann::json obj0(nlohmann::json::object());
  nlohmann::json obj1{nlohmann::json::object()};
  nlohmann::json obj2 = nlohmann::json::object();
  std::cout << obj0.dump() << std::endl;
  std::cout << obj1.dump() << std::endl;
  std::cout << obj2.dump() << std::endl;

  nlohmann::json str0("hello");
  nlohmann::json str1{"hello"};
  nlohmann::json str2 = "hello";
  std::cout << str0.dump() << std::endl;
  std::cout << str1.dump() << std::endl;
  std::cout << str2.dump() << std::endl;

  nlohmann::json array0(nlohmann::json::array());
  nlohmann::json array1{nlohmann::json::array()};
  nlohmann::json array2 = nlohmann::json::array();
  std::cout << array0.dump() << std::endl;
  std::cout << array1.dump() << std::endl;
  std::cout << array2.dump() << std::endl;

  return 0;
}

Output:

{}
{}
{}
"hello"
["hello"]
"hello"
[]
[]
[]

Error messages

No response

Compiler and operating system

Apple clang version 15.0.0 (clang-1500.1.0.2.5)

Library version

3.11.3

Validation

gregmarr commented 4 months ago

See the first entry in the FAQ. https://json.nlohmann.me/home/faq/

TobiSchluter commented 1 month ago

Perhaps it's worth adding a big something like this example to the faq and to warn about brace-initialization right where I guess most people look up the syntax for initialization (https://github.com/nlohmann/json?tab=readme-ov-file#json-as-first-class-data-type):

#include <format>
#include <iostream>
#include <nlohmann/json.hpp>

int main()
{
    nlohmann::json j1 = nlohmann::json::object({});
    nlohmann::json j2{ j1 };
    nlohmann::json j3( j1 );

    std::print(std::cout, "is j1 an object? {} an array? {}\n", j1.is_object(), j1.is_array());
    std::print(std::cout, "is j2 an object? {} an array? {}\n", j2.is_object(), j2.is_array());
    std::print(std::cout, "is j3 an object? {} an array? {}\n", j3.is_object(), j3.is_array());
}

Output:

is j1 an object? true an array? false
is j2 an object? false an array? true
is j3 an object? true an array? false

Run it here: https://godbolt.org/z/9YTbfEWo9