我已经从这个答案改编了一些代码来处理目标变体是源变体的子集的情况,如下所示:
template <class... Args>
struct variant_cast_proxy
{
std::variant<Args...> v;
template <class... ToArgs>
operator std::variant<ToArgs...>() const
{
return std::visit(
[](auto&& arg) -> std::variant<ToArgs...> {
if constexpr (std::is_convertible_v<decltype(arg), std::variant<ToArgs...>>)
return arg;
else
throw std::runtime_error("bad variant cast");
},
v
);
}
};
template <class... Args>
auto variant_cast(const std::variant<Args...>& v) -> variant_cast_proxy<Args...>
{
return { v };
}
struct A {};
struct B {};
struct C {};
struct D {};
struct E {};
struct F {};
int main() {
std::variant<A, B, C, D> v1 = B();
std::variant<B,C> v2;
v2 = variant_cast(v1);
}
上述方法有效,但我希望它能够处理在编译时可以检测到错误转换的情况。以上处理了运行时所有错误的转换,但运行时和编译时错误都是可能的。如果 v 持有 C 类型的值,则将 v类型std::variant<A,B,C>
转换为std::variant<A,B>
应该在运行时失败,但是例如
std::variant<A, B, C, D> v1 = B();
std::variant<E,F> v2;
v2 = variant_cast(v1)
甚至不应该编译。
我相信这可以通过 std::enable_if 完成,但我不确定它似乎需要测试可变参数包的集合包含,我不知道该怎么做。