初始化 std::variant 的映射以表示 JSON 文件

Initialize a map of std::variant to represent a JSON file

作为学校项目的一部分,我必须读取 JSON 配置文件来填充定义如下的自定义 Conf 对象:

struct ConfValue;
using ConfObject = std::map<std::string, ConfValue>;
using ConfArray = std::vector<ConfValue>;

/**
* Represents a configuration value.
*/
struct ConfValue {
    std::variant<std::monostate, ConfObject, ConfArray, std::string, long long, double, bool> v;
};

/**
* Configuration (format influenced by JSON).
*/
using Conf = ConfObject;

我希望能够构造一个由此 JSON 文件表示的默认对象:

{
      "port": 4242,
      "module": "modheader",
      "modulePath": ["../modules/", "./modules"]
}

它可以为我提供在真实配置文件中搜索的内容的映射、每个字段的类型以及每个字段的默认值。

我尝试使用支撑初始化来做到这一点,但无论我尝试什么,都无法编译:

  Conf default_conf_{
    {"port", ConfValue{4242}},
    {"module", ConfValue{"modHeader"}},
    {"modulePath", ConfArray{"../modules/", "./modules"}}
  };

我想用 C++ 做的事情是否可行?如果可行,怎么做? :)

附带问题:是否可以在 运行 时获取 std::variant 的类型?

您可能会使用:

Conf default_conf {
    {"port", ConfValue{4242LL}},
    {"module", ConfValue{"modHeader"}},
    {"modulePath", ConfValue{ConfArray{ConfValue{"../modules/"}, ConfValue{"./modules"}}}}
};

Demo

这里有两个独立的问题。

首先,如果没有更多帮助,4242 将无法工作。您可以将其减少为:

std::variant<long long, bool> v = 4242; // error

转换不明确。所以你必须做出一个更好的匹配。因此,4242LL.

其次,您只需要在 modulePath 值中添加更多大括号 - 因为我们需要列表初始化所有 ConfValue,我们不能只构造它们:

Conf default_conf_{{
  {"port", {4242LL}},
  {"module", {"modHeader"}},
  {"modulePath", {ConfArray{{"../modules/"}, {"./modules"}}}}
}};   

您基本上需要 ConfArray 来识别所有这些大括号的含义。如果您向 ConfValue 添加了一些构造函数,您也可以取消它。