Я адаптировал некоторый код из этого ответа для обработки случая, когда целевой вариант является подмножеством исходного варианта, следующим образом:
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 типа std::variant<A,B,C>
к std::variant<A,B>
должно завершиться неудачно во время выполнения, если v содержит значение типа C, но, например,
std::variant<A, B, C, D> v1 = B();
std::variant<E,F> v2;
v2 = variant_cast(v1)
даже не должно компилироваться.
I Я полагаю, что это можно сделать с помощью std :: enable_if, но я не уверен, что именно так, как кажется, потребовалось бы тестирование на предмет наличия набора пакетов variadi c, что я понятия не имею, как это сделать.