用c++17 variant实现的json库,想实现用 {} 大括号快速构建一个嵌套的json对象,但是加入了initializerlist后出现了灾难性的构造问题,无法构造数组、对象类型,更无法构建复杂的嵌套类型。如果去掉其中一个列表初始化,只保留构建数组的初始化列表,也不能实现匹配的问题,除非在构造时手动标明类型,但这和列表初始化的初衷完全背离了
main
#include "include/json/json.h"
#include <iostream>
using myjson::Json;
using std::cin, std::cout, std::endl;
int main(int, char **) {
// 数组也无法用initializer_list构造,除非将部分单参数构造变为隐式,但这本质就是错误的,可能导致一系列问题
Json json_1 { 3.141, 2, 17};
// Json json2
// {
// {"pi", 3.141},
// {"happy", true},
// {"name", "Niels"},
// {"nothing", nullptr},
// {
// "answer", {
// {"everything", 42}
// }
// },
// {"list", {1, 0, 2}}
// };
cout<<json_1.is_array()<<endl;
cout<<json_2.is_object()<<endl;
return 0;
}
json.h
#pragma once
#include <cstddef>
#include <initializer_list>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <utility>
#include <variant>
#include <vector>
namespace myjson {
class Json;
template <typename... Ts> struct overload : Ts... {
using Ts::operator()...;
};
template <typename... Ts> overload(Ts...) -> overload<Ts...>;
using JsonArray = std::vector<Json>;
using JsonObject = std::unordered_map<std::string, Json>;
class Json {
public:
using ValueType = std::variant<std::nullptr_t, bool, int, double, std::string,
JsonArray, JsonObject>;
public:
Json() : m_value(nullptr) {}
Json(const Json &) = default;
Json(Json &&) = default;
~Json() = default;
// 从基本类型构造
Json(std::nullptr_t) : m_value(nullptr) {}
explicit Json(bool value) : m_value(value) {}
// 防止 bool 构造为 int
template<typename Int, typename = std::enable_if_t<std::is_integral_v<Int>
&& !std::is_same_v<Int, bool>>>
explicit Json(int value) noexcept : m_value(static_cast<int>(value)) {}
explicit Json(double value) : m_value(value) {}
explicit Json(const std::string& value) : m_value(value) {}
//const char* 是否需要构造存疑
// explicit Json(const char* value) : m_value(std::string(value)) {}
explicit Json(JsonArray value) : m_value(std::move(value)) {}
explicit Json(JsonObject value) : m_value(std::move(value)) {}
Json(std::initializer_list<Json> init){
JsonArray array;
for (const auto& element : init) {
array.emplace_back(element);
}
m_value = std::move(array);
}
// object initializer_list构造
// Json(std::initializer_list<std::pair<const std::string, Json>> init) {
// JsonObject dict;
// for (const auto& p : init) {
// dict.insert(p);
// }
// m_value = std::move(dict);
// }
Json &operator=(const Json &other) = default;
Json &operator=(Json &&other) = default;
public:
[[nodiscard]] constexpr bool is_boolean() const noexcept {
return std::holds_alternative<bool>(m_value);
}
[[nodiscard]] constexpr bool is_integer() const noexcept {
return std::holds_alternative<int>(m_value);
}
[[nodiscard]] constexpr bool is_null() const noexcept {
return std::holds_alternative<nullptr_t>(m_value);
}
[[nodiscard]] constexpr bool is_double() const noexcept {
return std::holds_alternative<double>(m_value);
}
[[nodiscard]] constexpr bool is_string() const noexcept {
return std::holds_alternative<std::string>(m_value);
}
[[nodiscard]] constexpr bool is_array() const noexcept {
return std::holds_alternative<JsonArray>(m_value);
}
[[nodiscard]] constexpr bool is_object() const noexcept {
return std::holds_alternative<JsonObject>(m_value);
}
template <typename T> const T &get() const {
if (!std::holds_alternative<T>(m_value))
throw std::runtime_error("type mismatch");
return std::get<T>(m_value);
}
template <typename T> T &get() {
if (!std::holds_alternative<T>(m_value))
throw std::runtime_error("type mismatch");
return std::get<T>(m_value);
}
JsonArray as_array() {
if (!is_array())
throw std::runtime_error("Not an array");
return get<JsonArray>();
}
JsonObject as_dict() {
if (!is_object())
throw std::runtime_error("Not an dict");
return get<JsonObject>();
}
private:
ValueType m_value;
};
} // namespace myjson