I am really struggling with this variadic templates problem (I hope my problem statement is clear, otherwise, make me know if I’m not).
I have a struct defined as this:
// Args are types (all the time)
template<typename T, typename ...Args>
struct my_struct;
Then we declare two separate classes that have a member variable each, of my_struct
struct A { my_struct<A, int, int, char> _a_var; };
struct B { my_struct<B, int, int, char> _b_bar; };
// This way of instatiate my_struct must be as above, T => is the object that owns
// my_struct variable and the parameter pack must be the same.
// -This is relevan for the problem, I guess, :) -
And then we have another struct that defines a tuple
template<typename ...Types>
struct params
{
using tuple_params = typename std::tuple<Types...>;
}
And finally where the problem lies The third structure takes as first parameter an instance of params and another parameter pack And there is a method that will take objects that have an instance of my_struct and must_be_params must have the same types as that instance of my_struct
template<typename must_be_params, typename ...objects>
struct my_problem{
};
// Create a my_project instance
void some_random_function() {
A _a;
B _b;
// Note that params<> have the same types as the instances of my_struct
// in A and B
my_problem<params<int, int, char>, A, B> _my;
}
Detailing more of the definition of my_struct, now we have a new member function as this:
template<typename must_be_params, typename ...objects>
struct my_problem{
template<typename R, typename ...types>
void some_random_method( my_struct<R, types...> *ptr) {
}
};
THE ACTUAL PROBLEM (long story :) )
I want to have a vector of variants that can hold all the pointers of some_random_method in this way:
struct my_problem{
template<typename R, typename ...types>
void some_random_method( my_struct<R, types...> *ptr) {
_vector.emplace_back(ptr);
}
private:
// ASSUMING OBVIOUSLY THAT my_problem was declare as in some_random_function
// my_problem<params<int, int, char>, A, B> _my;
std::vector<std::variant< my_struct<A, int, int, char> *, my_struct<B, int, int, char> *> _vector;
};
WHERE DOES THE PROBLEM LIES (And this is killing me because I can not get my head around the problem) Notice that the variant have the parameters (int, int, char), now, Where are those types defined within my_problem? well in my partial resolution, they reside in the tuple declared in params<>
So what I want and I just can resolve the issue is to unroll the parameters from the tuple and just insert them into the my_struct that lives inside the std::variant. As far as I know, I’m sure that it can be solved with std::tuple_element, std::index_sequence and some recursive templates black magic.
So far I have manage to do this (which I don’t really know if its the right approach):
template <typename... Types>
struct tuple_to_variant_impl {
using type = std::variant<Types...>;
};
template <typename... Types>
struct tuple_to_variant_impl<std::tuple<Types...>> {
using type = typename tuple_to_variant_impl<Types...>::type;
};
template <typename... Types>
using tuple_to_variant = typename tuple_to_variant_impl<Types...>::type;
template<typename must_be_params, typename ...objects>
struct my_problem{
template<typename R, typename ...types>
void some_random_method( my_struct<R, types...> *ptr) {
}
private:
template<typename ...l>
using type = typename std::tuple<my_problem<objects, l...>*...>;
std::vector<tuple_to_variant< type< must_be_params::tuple_params > > > _vector;
// must_be_params::tuple_params => is equal to std::tuple<int, int, char>
};
struct A { my_struct<A, int, int, char> _a_var; };
struct B { my_struct<B, int, int, char> _b_bar; };
void some_random_function() {
A _a;
B _b;
my_problem<params<int, int, char>, A, B> _my;
}
According to cppinsights (https://cppinsights.io)
this code expands to:
template<>
struct my_problem<signal_params<int, int, char>, A, B>
{
// ...
private:
template<typename ... l>
using type = std::tuple<my_struct<A, l...> *, my_struct<B, l...> *>;
std::vector<std::variant<my_struct<A, std::tuple<int, int, char> > *, my_struct<B, std::tuple<int, int, char> > *>, std::allocator<std::variant<my_struct<A, std::tuple<int, int, char> > *, my_struct<B, std::tuple<int, int, char> > *> > > _vector;
// ...
};
As you can see so far this technic expands to something like this
std::vector<
std::variant<
my_struct<A, std::tuple<int, int, char> > *,
my_struct<B, std::tuple<int, int, char> > *
>
> _vector;
BUT what I really want is to unroll the tuple types o create something like this
std::vector<
std::variant<
my_struct<A, int, int, char > *, // NOTICE: NO MORE std::tuple
my_struct<B, int, int, char > * // NOTICE: NO MORE std::tuple
>
> _vector;
How can it be done?
Partial specialization might be simpler:
template <typename must_be_params, typename... objects>
struct my_problem;
template <typename... Ts, typename... objects>
struct my_problem<params<Ts...>, objects...>
{
std::vector<std::variant<my_struct<objects, Ts...>*...> _vector;
};