Info
-
Did you know about the proposal to add json support to the standard library?
Example
int main() {
nlohmann::json json{};
json["value"] = 42;
json["array"] = std::array{1, 2, 3};
std::cout << json.dump(); // prints {"array":[1,2,3],"value":42}
}
Puzzle
- Can you implement
to_json
function which converts a given tuple of named fields intonlohmann::json
object?
constexpr auto to_json(const auto&); // TODO
template <class T>
struct named {
std::string_view name{};
T value{};
};
int main() {
using namespace boost::ut;
"to json"_test = [] {
"value"_test = [] {
const auto json = to_json(std::tuple{named{.name = "int", .value = 1}});
expect(1_i == json["int"].get<int>());
};
"array"_test = [] {
const auto json = to_json(
std::tuple{named{.name = "array", .value = std::array{1, 2}}});
expect(std::array{1, 2} == json["array"].get<std::array<int, 2>>());
};
"complex"_test = [] {
const auto json = to_json(std::tuple{
named{.name = "int", .value = 1},
named{.name = "double", .value = 2.0},
named{.name = "array", .value = std::array{1, 2, 3}},
named{.name = "compound",
.value = std::tuple{named{.name = "unsigned", .value = 42u}}}});
expect(1_i == json["int"].get<int>() and
2._d == json["double"].get<double>() and
std::array{1, 2, 3} == json["array"].get<std::array<int, 3>>() and
42_u == json["compound"]["unsigned"].get<unsigned>());
};
};
}
Solutions
constexpr auto& to_json(const auto& t) {
return t;
}
template <typename... Ts>
constexpr auto to_json(const std::tuple<Ts...>& t) {
return std::apply([] (const auto&... ts) {
nlohmann::json obj{};
((obj[std::string{ts.name}] = to_json(ts.value)), ...);
return obj;
}, t);
}
constexpr auto to_json(const auto& value) { return value; }
template <typename... Ts>
constexpr auto to_json(const std::tuple<Ts...>& tuple) {
nlohmann::json output;
std::apply(
[&output](const auto&... args) {
(..., [&output](const auto& arg) {
output[std::string{arg.name}] = to_json(arg.value);
}(args));
},
tuple);
return output;
}
constexpr auto to_json(const auto& value) -> decltype(auto) {
return value;
}
template <typename... Ts>
constexpr auto to_json(std::tuple<Ts...> const& tuple) {
nlohmann::json json{};
std::apply([&] (auto const&... named) {
((json[std::string{named.name}] = to_json(named.value)), ...);
}, tuple);
return json;
}
constexpr auto to_json(const auto& v) { return v; }
template <class... Ts>
constexpr auto to_json(const std::tuple<Ts...>& t) {
nlohmann::json o{};
(..., (o[std::string{std::get<Ts>(t).name}] = to_json(std::get<Ts>(t).value)));
return o;
}
template<class T>
constexpr auto to_json(const T& t) { return t; }
template<class ...T>
constexpr auto to_json(const std::tuple<named<T>...>& tup) {
nlohmann::json json{};
[&json, &tup] <auto ...Id> (std::index_sequence<Id...> const&) {
( (json[std::string(std::get<Id>(tup).name).c_str()] = to_json( std::get<Id>(tup).value)), ...);
}(std::make_index_sequence<sizeof...(T)>{});
return json;
}
constexpr auto to_json( auto const & arg){ return arg; }
template<class T>
constexpr std::tuple<const char*,decltype(to_json(T{}))> to_json( named<T> const & arg)
{
return {arg.name.data(),to_json(arg.value)};
}
template<class ... T>
constexpr auto to_json(std::tuple< named<T> ... > const & arg)
{
return std::apply( []( auto const & ...args ){ return nlohmann::json{to_json(args)...}; },arg);
}
constexpr auto to_json(const auto & value) {
return value;
}
template<class ...T> constexpr auto to_json(const std::tuple<named<T>...>& tp) {
nlohmann::json json{};
std::apply([&](const auto&... n)
{
((json[std::string{n.name}] = to_json(n.value)), ...);
}, tp);
return json;
};