【问题标题】:Can I use braced-init-list for a vector of std::variant?我可以将支撑初始化列表用于 std::variant 的向量吗?
【发布时间】:2018-02-15 17:28:51
【问题描述】:

我有 2 个保存不同数据的结构,每个都有一个方法可以将这些数据序列化为 JSON 字符串:

struct Struct1
{
  Struct1(int value) : value(value){};

  int value;

  std::string ToJSON() const
  {
    std::string ret = "{value: " + std::to_string(value) + "}";
    return ret;
  }
};

struct Struct2
{
  Struct2(std::string id, std::string image, std::string name) : id(id), image(image), name(name){};

  std::string id;
  std::string image;
  std::string name;

  std::string ToJSON() const
  {
    return "{id: " + id + " image: " + image + " name: " + name + "}";
  }
};

我需要将其中的几个存储在一个容器中,以便以后迭代它们并从每个对象中获取 JSON 字符串。我使用std::variant 执行此操作。

std::vector<std::variant<Struct1, Struct2>> v3;

然后我可以像这样遍历容器:

auto GetJSONString = [](auto&& _in){return _in.ToJSON();};

for (const auto& nextV : v3)
{
  auto test = std::visit(GetJSONString, nextV);
  std::cout << test << " ";
}
std::cout << std::endl;

在我尝试使用braced-init-lists 填充向量之前,一切正常。

换句话说,这是有效的:

std::vector<std::variant<Struct1, Struct2>> v{Struct1(5), Struct2("someid", "someimage", "somename")};

但这不是:

std::vector<std::variant<Struct1, Struct2>> v4{ {13}, {"someid", "someimage", "somename"}};

在不工作的代码上,我收到以下编译器错误:

error: no matching function for call to 'std::vector<std::variant<Struct2, Struct1> >::vector(<brace-enclosed initializer list>)

我不明白这是为什么。在这种情况下我不能使用大括号初始化吗?如果是这样,……为什么?或者我是否需要以某种方式修改我的结构以支持这种初始化?

Here 是 wandbox.org 上的一个最小工作示例,以进一步说明我的问题。

【问题讨论】:

    标签: c++ initialization variant c++17


    【解决方案1】:

    在这种情况下我不能使用大括号初始化吗?如果是这样,……为什么?或者我是否需要以某种方式修改我的结构以支持这种初始化?

    不,你不能。不,您无法进行任何更改以使其正常工作。这是一个非常简化的示例:

    template <typename T> void foo(T&& );
    foo({1}); // what is T?
    

    支撑初始化列表没有类型,因此无法推断。 variant 的构造函数的工作方式是推导出其参数,然后从中选择最佳替代方案进行初始化。它不能从您的支撑初始化列表中做到这一点,您必须使用具有类型的表达式。

    如果variant&lt;A, B, C&gt; 本身具有非模板 构造函数variant(A&amp;&amp; )variant(B&amp;&amp; )variant(C&amp;&amp; ),则可以使这工作的唯一方法。 那么,braced-init-lists 就可以了。

    【讨论】:

      【解决方案2】:

      你打算让你的代码调用的variant constructor

      template<typename T>
      constexpr variant(T&& t)
      

      但是该构造函数模板的模板参数推导将失败,因为braced-init-lists do not have a type

      您可以使用以std::in_place_type_t&lt;T&gt; 作为第一个参数的构造函数更接近一点

      std::vector<std::variant<Struct2, Struct1>> v4{
           { std::in_place_type<Struct1>, 13 },
           { std::in_place_type<Struct2>, "someid", "someimage", "somename" }
      };
      

      但这也失败了,因为有问题的variant 构造函数是explicit,即ill-formed for copy-list-initialization

      所以你列出的选项是最好的一个

      std::vector<std::variant<Struct2, Struct1>> v4{
           Struct1{ 13 },
           Struct2{ "someid", "someimage", "somename" }
      };
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-07-23
        • 2021-04-25
        • 2012-05-01
        • 2012-01-18
        • 2017-10-24
        相关资源
        最近更新 更多