Этот код принимает объект std::any
вместе со списком типов и преобразует объект в std::variant
или выдает std::bad_any_cast
, если сохраненный тип не относится к одному из указанных типов.
#include <any>
#include <variant>
#include <optional>
#include <typeinfo>
template <class... Args>
auto any_to_variant_cast(std::any a) -> std::variant<Args...>
{
if (!a.has_value())
throw std::bad_any_cast();
std::optional<std::variant<Args...>> v = std::nullopt;
bool found = ((a.type() == typeid(Args) && (v = std::any_cast<Args>(std::move(a)), true)) || ...);
if (!found)
throw std::bad_any_cast{};
return std::move(*v);
}
Пример использования:
auto test(const std::any& a)
{
auto v = any_to_variant_cast<int, std::string>(a);
std::visit([](auto val) { std::cout << val << std::endl; }, v);
}
Код на Godbolt
Некоторые пояснения:
std::optional<std::variant<Args...>>
используется, потому что std::variant<Args...>
конструктор по умолчанию создает вариант, содержащий инициализированное значением первой альтернативы, и требует, чтобы первая альтернатива была конструируемой по умолчанию.
((a.type() == typeid(Args) && (v = std::any_cast<Args>(std::move(a)), true)) || ...)
// ------------------------ -------------------------------------
// type_check any_cast
Это выражение сгиба, Я переименовал некоторые подвыражения, чтобы их было легче объяснить. При переименовании выражение становится:
// ((type_check && (any_cast, true)) || ...)
- , если
type_check
равно false
, то: (any_cast, true)
не оценивается из-за короткого замыкания &&
(type_check && (any_cast, true))
оценивается как false
- , следующий оператор в выражении сгиба оценивается
- , если
type_check
равно true
, то : (any_cast, true)
оценивается: any_cast
оценивается. Вариант получает значение из любого объекта. any_cast
результат отбрасывается true
оценивается (any_cast, true)
оценивается как true
(type_check && (any_cast, true))
оценивается как true
- остальная часть сгиба не оценивается из-за короткого замыкания
||
- всего выражения ( сгиб) оценивается как
true
- , если нет
type_check
, оценивается как true
, тогда все выражение (сгиб) оценивается как false