3

I'm given a std::variant of several types. I would like to write a trait that gives another std::variant of the pointer of the types of the first.

using MyVariant = std::variant<int, float>;

using MyVariantOfPointers = pointer_of_v<MyVariant>;

such that MyVariantOfPointer is std::variant<int*, float*>. I tried to play with std::variant_size_v and std::variant_alternative_t but I do not know how to build the new type recursively.

2 Answers 2

3

You can use partial specialization to write a trait to solve this.

// General case
template<class T>
struct VariantToPtrVariant;

// Partial specialization when used with std::variant
// Extracts the template arguments from the `std::variant` and 
//  produces a new `std::variant` with those types, with an added `*`
template<class ... T>
struct VariantToPtrVariant<std::variant<T...>> {
    using type = std::variant<T*...>;
};

// Helper variable template
template<class T>
using VariantToPtrVariant_t = typename VariantToPtrVariant<T>::type;

Usage :

using MyVariant = std::variant<int, float>;
using MyVariantOfPointers = VariantToPtrVariant_t<MyVariant>;

Complete example (https://godbolt.org/z/qaTxo4nzc) :

#include <type_traits>
#include <variant>

template<class T>
struct VariantToPtrVariant;

template<class ... T>
struct VariantToPtrVariant<std::variant<T...>> {
    using type = std::variant<T*...>;
};

template<class T>
using VariantToPtrVariant_t = typename VariantToPtrVariant<T>::type;

using MyVariant = std::variant<int, float>;
using MyVariantOfPointers = VariantToPtrVariant_t<MyVariant>;

static_assert(std::is_same_v<MyVariantOfPointers, std::variant<int*, float*>>);

Sign up to request clarification or add additional context in comments.

Comments

1

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

2 Comments

This one won't obviously work for anything with default template args, like vector for instance. I mean it will transform everything into pointers of course, but that wouldn't be what any sane user could expect. godbolt.org/z/43qPzYx4v
Yes obviously. It won't work with bananas also, obviously.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.