0

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)>(); }...
            };
Brosbiln
  • 23
  • 4
  • Are you looking for something like that as signature: `template void next(std::variant& v, const std::tuple& value_to_emplace)`? – Jarod42 Nov 16 '22 at 16:23
  • At the end, I need something like this (don't know if it is possible though): `template void next(std::variant& v, int typeIndex, void* ptrToData)` – Brosbiln Nov 16 '22 at 19:40
  • I wonder how you call it. I meant how do you ensure type of `ptrToData`? if type is knows, a simple `v = data;` would do the job. if you use some kind of type erasure, why not use directly a variant? – Jarod42 Nov 17 '22 at 15:14

2 Answers2

0

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

Nimrod
  • 2,908
  • 9
  • 20
0

You can adapt provided code to:

template <typename... Ts, std::size_t... Is>
void set(std::variant<Ts...>& v, std::index_sequence<Is...>, std::size_t index, void* data)
{
    using Func = void (*)(std::variant<Ts...>&, void*);
    Func funcs[] = {
        +[](std::variant<Ts...>& v, void* data){
            using T = std::variant_alternative_t<Is, std::variant<Ts...>>;
            v.template emplace<Is>(*reinterpret_cast<T*>(data));
        }...
    };
    funcs[index](v, data);
}

template <typename... Ts>
void set(std::variant<Ts...>& v, std::size_t index, void* data)
{
    set(v, std::make_index_sequence<sizeof...(Ts)>(), index, data);
}

Demo

Note though that your interface is fragile: data should be of the correct type, else you have UB.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Thank you for help. It's a templated wrapper of IPC based on shared memory. I just use a variant to return a specific pointer to a message buffer, instead of void* and a type index. – Brosbiln Nov 17 '22 at 17:37