I am trying to convert a list of template arguments (enum class, not typenames) to corresponding typenames for the template arguments to an std::tuple. I'm guessing if I can get somehow name the variadic list as a using type = ...
, I might be able to expand that in the next template recursion
So, I have the enum class:
enum class object_t{
STR,
INT,
FLOAT,
};
and the template supposed to provide the concrete class (some std::tuple):
template <object_t _obj, object_t ...Args>
struct concrete {
// here's the part I need to correct
using type = std::tuple<typename concrete<_obj>::type, typename concrete<Args...>::type>;
};
the specializations to tail off the recursions:
template <>
struct concrete<object_t::STR> {
using type = std::string;
};
template <>
struct concrete<object_t::INT> {
using type = int64_t;
};
template <>
struct concrete<object_t::FLOAT> {
using type = double;
};
and the using declaration for the ::type shorthand
template<object_t _obj, object_t ...Args>
using concrete_t = typename concrete<_obj, Args...>::type;
Eventually, I want something like
concrete_t<object_t::INT, object_t::FLOAT, object_t::STR>
to be equivalent to
std::tuple<int64_t, double, std::string>
Currently, that should produce something like:
std::tuple<int64_t, std::tuple<double, std::string>>
instead.
I'm not the best on variadic templates, but i'm thinking if the using type (of the general template) was a parameter pack instead of a tuple, I might be able to unpack it for the next tuple (whose parameter list I will then have to obtain again and so on). Something like:
template <object_t _obj, object_t ...Args>
struct concrete {
using type = std::tuple<typename concrete<_obj>::type, typename concrete<Args...>::type...>::elements_type;
};
where the elements_type is a variadic pack and the ::type... unpacks it
But even that doesn't seem right, since the root ::type will be a parameter pack and not an std::tuple like desired. Maybe another template is needed, I do not know.
Anything advice might go a long way, thanks!
In case someone needs this, the solution, thanks to @IgorTandetnik, looks like this:
enum class object_t{
STR,
INT,
FLOAT,
};
template<object_t _obj>
struct concrete_traits;
template<>
struct concrete_traits<object_t::STR> {
using type = std::string;
};
template<>
struct concrete_traits<object_t::INT> {
using type = int64_t;
};
template<>
struct concrete_traits<object_t::FLOAT> {
using type = double;
};
template <object_t ...Args> struct concrete {
using type = std::tuple<typename concrete_traits<Args>::type...>;
};
template<object_t ...Args>
using concrete_t = typename concrete<Args...>::type;
This answer is based on @IgorTandetnik comment.
To eliminate the std::tuple in the trivial case of a single template argument, the specialization
template<object_t _obj>
struct concrete<_obj> {
using type = typename concrete_traits<_obj>::type;
};
makes, for example, concrete_t<object_t::STR>
to be std::string
instead of std::tuple<std::string>
.