I have run into a strange challenge trying to define a type based on an array while writing some library binding code.
Consider an enumeration like the following:
enum class MyTypes
{
UInt,
Int,
Float
}
With some type traits, I can convert a value of the enumeration into a type:
template <MyTypes Ty> struct typeify;
template <> struct typeify<MyTypes::UInt> { using type = unsigned int; };
template <> struct typeify<MyTypes::Int> { using type = int; };
template <> struct typeify<MyTypes::Float> { using type = float; };
template <MyTypes Ty> using typeify_t = typename typeify<Ty>::type;
To help with the binding, I also have this (because C++ doesn't have reflection):
inline static constexpr std::array KnownTypes
{
std::pair{"UInt", MyTypes::UInt},
std::pair{"Int", MyTypes::Int},
std::pair{"Float", MyTypes::Float}
};
From here, I want to define a std::variant
based on my known types.
With 3 values, the obvious thing is to just write the variant like so:
std::variant<unsigned int, int, float>
But, in my situation, I have 50+ types. So, I would like a way to automatically generate the type definition for the std::variant
from the array of KnownTypes
and the typeify_t
type trait.
I think I have gotten close with the following, but I have been stymied by not being able to give a variadic template parameter a default value:
template <template <typename T, T ... Idx> class temp = std::make_index_sequence<KnownTypes.size()>>
using AnyKnownType = std::variant<typeify_t<KnownTypes[Idx].second>, ...>;
Any problem in programming can be solved with another level of indirection (except too many levels of indirection).
Instead of directly creating a using
expression template, create a function template declaration and use its return type in your using
expression:
template <std::size_t... Is>
std::variant<typeify_t<KnownTypes[Is].second>...>
make_variant_type(std::index_sequence<Is...>);
using AnyKnownType = decltype(make_variant_type(std::make_index_sequence<KnownTypes.size()>()));