Although I already posted an answer to my own question, and I accepted an answer from another user, I thought I could post another possibility in tackling this problem using the following struct
template <typename... Ts> struct type_sequence { };
which I learnt about in this talk by Andrei Alexandrescu. Since I learnt quite a bit by using it and the result is a bit simpler than the original answer that used two nested structs I thought I would share it here. However, the solution I would actually implement is the one that was accepted.
This is the full code with a main function included. Notice the change in the specification of function return_something. Now this function indicates the return type (which I like very much, perhaps I'm old fashioned) in a more readable way than in my first answer. You can try it out here.
#include <type_traits>
#include <iostream>
#include <vector>
template <bool... values>
struct which {
    template <std::size_t idx, bool v1, bool... vs>
    struct _which_impl {
        static constexpr std::size_t value =
            (v1 ? idx : _which_impl<idx + 1, vs...>::value);
    };
    template <std::size_t idx, bool v>
    struct _which_impl<idx, v> {
        static constexpr std::size_t value = (v ? idx : idx + 1);
    };
    static constexpr std::size_t value = _which_impl<0, values...>::value;
};
template <std::size_t ith_idx, typename... Ts>
struct ith_type {
    template <std::size_t cur_idx, typename t1, typename... ts>
    struct _ith_type_impl {
        using type =
            std::conditional_t<
                ith_idx == cur_idx,
                t1,
                typename _ith_type_impl<cur_idx + 1, ts...>::type
            >;
    };
    template <std::size_t cur_idx, typename t1>
    struct _ith_type_impl<cur_idx, t1> {
        using type = std::conditional_t<ith_idx == cur_idx, t1, std::nullptr_t>;
    };
    using type = typename _ith_type_impl<0, Ts...>::type;
};
template <std::size_t ith_idx, typename... ts>
using ith_type_t = typename ith_type<ith_idx, ts...>::type;
template <bool... conds>
static constexpr std::size_t which_v = which<conds...>::value;
template <typename... Ts> struct type_sequence { };
template <bool... values> struct bool_sequence {
    static constexpr std::size_t which = which_v<values...>;
};
template <std::size_t ith_idx, typename... Ts>
struct ith_type<ith_idx, type_sequence<Ts...>> : ith_type<ith_idx, Ts...>
{ };
template <typename bool_sequence, typename type_sequence>
struct conditional_list {
    using type = ith_type_t<bool_sequence::which, type_sequence>;
};
template <typename bool_sequence, typename type_sequence>
using conditional_list_t =
    typename conditional_list<bool_sequence, type_sequence>::type;
enum class list_whats {
    what1,
    what2,
    what3,
    what4,
    what5,
};
template <list_whats what>
conditional_list_t<
    bool_sequence<
        what == list_whats::what1,
        what == list_whats::what2,
        what == list_whats::what3,
        what == list_whats::what4,
        what == list_whats::what5
    >,
    type_sequence<
        int,
        float,
        double,
        std::string,
        std::vector<int>
    >
>
return_something() noexcept {
    if constexpr (what == list_whats::what1) { return 1; }
    if constexpr (what == list_whats::what2) { return 2.0f; }
    if constexpr (what == list_whats::what3) { return 3.0; }
    if constexpr (what == list_whats::what4) { return "42"; }
    if constexpr (what == list_whats::what5) { return {1,2,3,4,5}; }
}
int main() {
    [[maybe_unused]] auto s1 = return_something<list_whats::what1>();
    [[maybe_unused]] auto s2 = return_something<list_whats::what2>();
    [[maybe_unused]] auto s3 = return_something<list_whats::what3>();
    [[maybe_unused]] auto s4 = return_something<list_whats::what4>();
    [[maybe_unused]] auto s5 = return_something<list_whats::what5>();
}