Home > database >  Create std::variant from another with a sub set of the types
Create std::variant from another with a sub set of the types

Time:08-22

Seen some other questions about this but they so not seem to be answered correctly or there is no answer at all.

I have a instance of a std::variant and I want to create another instance with a sub set of the types in the first one as I know the original is not that type. For exmaple...

std::varaint<int, const char*, bool> v1 = false;
std::varaint<int, bool> v2 = cast_variant<int, bool>(v1);

As you can see I can guarantee v1 does have a value that is in the list of types for v2. Just wondering how you would implement this or can you?

CodePudding user response:

you can use std::visit to get the item, then create new std::variant from it

template <typename...Ts, typename...Us>
std::variant<Ts...> cast_variant(const std::variant<Us...>& variant){
    return std::visit(
        [&](auto&& v)->std::variant<Ts...>{
            // or you can check if type of v inside Ts... 
            if constexpr(requires {std::variant<Ts...>{v};}) 
                return v;
            else
                throw std::bad_variant_access();
        }
        ,variant
    );
}

CodePudding user response:

@appleapple already provided an answer. However,

if constexpr(requires {std::variant<Ts...>{v};})

This can easily triggers implicit conversion, so the below code will work without throwing any exceptions:

std::varaint<int, const char*, bool> var1 = false;
auto var2 = cast_variant<int>(var1); // convert `false` to int

Instead, consider explicitly checking if current type is included in new types:

template<typename ... newTypes, typename ... oldTypes>
auto cast_variant(const std::variant<oldTypes...>& var) {
    return std::visit([]<typename T>(T && arg) -> std::variant<newTypes...> {
        if constexpr (std::disjunction_v<std::is_same<std::decay_t<T>, newTypes>...>) {
            return arg;
        }
        else {
            throw std::bad_variant_access();
        }
    }, var);
}
  • Related