Search code examples
c++templatesstd-variant

emplace pointer as proper type into std::variant in template


Is it possible to emplace some void* pointer into variant with a runtime generated index.

Can this nice solution (from here link), be updated to get index and pointer to emplace?

#include <variant>

template <typename... Ts, std::size_t... Is>
void next(std::variant<Ts...>& v, std::index_sequence<Is...>)
{
    using Func = void (*)(std::variant<Ts...>&);
    Func funcs[] = {
        +[](std::variant<Ts...>& v){ v.template emplace<(Is + 1) % sizeof...(Is)>(); }...
    };
    funcs[v.index()](v);
}

template <typename... Ts>
void next(std::variant<Ts...>& v)
{
    next(v, std::make_index_sequence<sizeof...(Ts)>());
}

It is possible to get the required data type, but don't think it helps anyway

           Func funcs[] = {
                [](MessageTypesVariant& v) {
                    auto y = std::get<(Is)>(v);
                    auto z = std::forward<decltype(y)>(y);
                    v.template emplace<(Is)>(); }...
            };

Solution

  • You can do it like this, unpack Ts... and check if the type matches.

    template <typename T, typename... Ts>
    bool set(std::variant<Ts*...>& v, int typeIndex, void* ptrToData) {
        constexpr static auto idx = index_v<T, Ts...>;
        if (idx == typeIndex) {
            v.template emplace<idx>(static_cast<T*>(ptrToData));
            return true;
        }
        return false;
    }
    
    template <typename... Ts>
    void set(std::variant<Ts*...>& v, int typeIndex, void* ptrToData) {
        (set<Ts, Ts...>(v, typeIndex, ptrToData) || ...);
    }
    

    Here, you need a way to index a type from a typelist, index_v, a common tech used in typelist.

    // index
    inline constexpr std::size_t npos = -1;
    
    template <typename T, typename... Ts>
    struct index : std::integral_constant<std::size_t, npos> {};
    
    template <typename T, typename... Ts>
    inline constexpr std::size_t index_v = index<T, Ts...>::value;
    
    template <typename T, typename... Ts>
    struct index<T, T, Ts...> : std::integral_constant<std::size_t, 0> {};
    
    template <typename T, typename Head, typename... Tail>
    class index<T, Head, Tail...> {
        static constexpr std::size_t tmp = index_v<T, Tail...>;
    
    public:
        static constexpr std::size_t value = tmp == npos ? tmp : tmp + 1;
    };
    

    Demo