I would like to use the type information from a class template argument list.
Working example with quick workaround:
struct NoParam {};
template< typename A = NoParam,
typename B = NoParam,
typename C = NoParam,
typename D = NoParam,
typename E = NoParam,
typename F = NoParam >
struct TypeList
{
typedef A T1;
typedef B T2;
typedef C T3;
typedef D T4;
typedef E T5;
typedef F T6;
};
template<typename... Types>
class Application
{
Application()
{
// the actual code will store the created instances in a tuple or map..
std::make_unique< TypeList<Types...>::T1 > ();
std::make_unique< TypeList<Types...>::T2 > ();
std::make_unique< TypeList<Types...>::T3 > ();
std::make_unique< TypeList<Types...>::T4 > ();
std::make_unique< TypeList<Types...>::T5 > ();
std::make_unique< TypeList<Types...>::T6 > ();
}
}
Is there any generic way...
A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)
There are three kinds of templates: function templates, class templates and, since C++14, variable templates. Since C++11, templates may be either variadic or non-variadic; in earlier versions of C++ they are always non-variadic.
In C++ this can be achieved using template parameters. A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.
Class Template Argument Deduction (CTAD) is a C++17 Core Language feature that reduces code verbosity. C++17's Standard Library also supports CTAD, so after upgrading your toolset, you can take advantage of this new feature when using STL types like std::pair and std::vector.
Do not re-invent the wheel, you can use std::tuple
and std::tuple_element_t
for that:
template<typename... T>
using TypeList = std::tuple<T...>;
template<int I, typename T>
using Type = std::tuple_element_t<I, T>;
template<typename... Types>
class Application {
Application() {
std::make_unique<Type<0, TypeList<Types...>>> ();
std::make_unique<Type<1, TypeList<Types...>>> ();
// and so on...
}
}
Iterate over the types is quite simple now.
It follow a minimal, working example to show you how you can do that:
#include <tuple>
#include <functional>
#include <memory>
template<typename... T>
using TypeList = std::tuple<T...>;
template<int I, typename T>
using Type = std::tuple_element_t<I, T>;
template<typename... Types>
class Application {
using MyTypeList = TypeList<Types...>;
template<std::size_t... I>
void iterate(std::index_sequence<I...>) {
// demonstration purposes, here I'm simply creating an object of the i-th type
int _[] = { 0, (Type<I, MyTypeList>{}, 0)... };
(void)_;
}
public:
void iterate() {
iterate(std::make_index_sequence<sizeof...(Types)>{});
}
Application() {
std::make_unique<Type<0, MyTypeList>> ();
std::make_unique<Type<1, MyTypeList>> ();
// and so on...
}
};
int main() {
Application<int, float> app;
app.iterate();
}
Note that std::index_sequence
and std::make_index_sequence
are available since C++14. Anyway, you can find online several implementations to be used if you are constrained to C++11.
Otherwise, you can also iterate over the types with a couple of recursive _sfinae'd_functions that check if sizeof...(Types)
has been reached.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With