Another solution providing a generic solution: apply any type functor on any type collection:
// Map Template Functor
template<template<class> class Functor, class TCollection>
struct map {};
template<template<class> class Functor, template<class...> class TCollection, class... Types>
struct map<Functor, TCollection<Types...>>
{
using type = TCollection<Functor<Types> ...>;
};
Usage example:
// Functor to map
template<typename T> using add_pointer_t = T*;
template<typename T> using add_reference_t = T&;
// Type collection to map on
using MyVariant = std::variant<int, float, double>;
using MyTuple = std::tuple<MyVariant, int, int>;
// Usage
using MyVariantOfPointers = map_t<add_pointer_t, MyVariant>;
using MyTupleOfPointers = map_t<add_reference_t, MyTuple>;
static_assert(std::is_same_v<MyVariantOfPointers, std::variant<int*, float*, double*>>);
static_assert(std::is_same_v<MyTupleOfPointers, std::tuple<std::variant<int, float, double>&, int&, int&>>);
Demo on Compiler Explorer