我可以向std :: variant <ts ...,ys ... =“”>分配/构造std :: variant <ts ...>吗?

时间:2018-12-31 09:45:02

标签: c++ c++17 variant boost-variant

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

那我为什么不能this呢?

#include <variant>

int main()
{
    std::variant<int> v1{42};
    std::variant<int, char> v2{v1}; // copy construction
    v2 = v1; // copy assignment
    v2 = std::move(v1); // move assignment
    std::variant<int, char> v3{std::move(v2)}; // move construction
}

从概念上讲,这似乎没问题。甚至boost::variant allows it(即使std和boost变体并不是完全相同的野兽)。我找不到缺陷报告或建议,所以我可能缺少了一些不允许使用C ++的黑角原因。

1 个答案:

答案 0 :(得分:2)

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

添加这样的转换构造函数和转换赋值运算符的唯一可能的技术问题是与当前变量的怪异病理相互作用。现在,variant<Ts...>的构造函数接受了T&&,并试图为其选择Ts。这有可能发生冲突,您必须在这里回答想要发生什么的问题:

struct X { X(variant<int>); };

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

当前,这是有效的,并且w拥有一个由X构造的v。您是否要更改此设置并让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);