我可以将 std::variant<Ts...> 分配给/从 std::variant<Ts..., Ys...> 分配/构造吗?

Posted

技术标签:

【中文标题】我可以将 std::variant<Ts...> 分配给/从 std::variant<Ts..., Ys...> 分配/构造吗?【英文标题】:Can I assign/construct an std::variant<Ts...> to/from an std::variant<Ts..., Ys...>? 【发布时间】:2018-12-31 09:45:01 【问题描述】:

在我看来,将可能是苹果或橙子的东西分配给可能是苹果、橙子或草莓的东西是明确定义的。

那为什么我不能this?

#include <variant>

int main()

    std::variant<int> v142;
    std::variant<int, char> v2v1; // copy construction
    v2 = v1; // copy assignment
    v2 = std::move(v1); // move assignment
    std::variant<int, char> v3std::move(v2); // move construction

从概念上讲,这似乎没问题。甚至boost::variant allows it(尽管 std 和 boost 变体并不完全相同)。我找不到缺陷报告或建议,所以我可能遗漏了一些 C++ 中不允许这样做的原因。

【问题讨论】:

您可能仍会执行以下操作:auto v1 = std::visit([](auto e) -&gt; std::variant&lt;int, char&gt; return e; , v2); 首先,通常的挑剔,你没有分配,你正在复制初始化。除此之外,为了使所述构造函数存在,它需要与c'tor (4) here 配合使用。它的规格看起来已经足够令人生畏了。 @Storyteller,对,我首先有一个复制任务,然后“简化”了代码。两者都有同样的问题。 编辑了问题以避开挑剔者;)。 【参考方案1】:

无论出于何种原因,标准库都不支持它。 std::variant 是一个非常漫长、非常有争议的过程。也许这个特定方面在任何人的名单上都不高?

添加这种转换构造函数和转换赋值运算符唯一可能的技术问题是与当前构造函数的奇怪的病态交互。现在,variant&lt;Ts...&gt; 有一个构造函数采用T&amp;&amp;,它试图为它选择一个Ts。这有可能发生冲突,你必须回答你想在这里发生什么的问题:

struct X  X(variant<int>); ;

variant<int>    v = 42;
variant<int, X> w = v;

目前,这是有效的,w 拥有一个由v 构造的X。你想改变这种情况并让w 持有int 42 吗?


目前,您只需手动完成:

template <typename To, typename From>
To variant_cast(From&& from) 
    return std::visit(
        [](auto&& elem)  return To(std::forward<Elem>(elem)); ,
        std::forward<From>(from));

你不会得到一个很好的语法(并且上面的实现对 SFINAE 不友好),但它可以完成工作:

using V2 = variant<int, char>;
auto v2 = variant_cast<V2>(v1);
v2 = variant_cast<V2>(v1);
v2 = variant_cast<V2>(std::move(v1));

// at least this one is stil easy :-)
auto v3 = std::move(v2);

【讨论】:

我认为 OP 想知道标准中是否有某些内容不允许这样做,因为 boost::variant 允许这样做。 @P.W 好吧,是的,标准实际上是不允许的。没有这样的构造函数/赋值运算符。 我猜你必须在 lambda 中写 return To(std::forward&lt;decltype(elem)&gt;(elem));Elem 没有在任何地方定义。

以上是关于我可以将 std::variant<Ts...> 分配给/从 std::variant<Ts..., Ys...> 分配/构造吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 boost::hana::tuple 转换为 std::variant

std::visit 无法推断 std::variant 的类型

如何将 std::variant 作为 VARIANT* 传递给 ExecWB?

使用类作为数据类型时如何在 std::variant 中存储值?

std::visit 和 std::variant 用法

std::variant 是不是提供类似于 boost::variant<>::types 的功能?