Introduction
My answer tries to be the prefered one for C++11 users.
Joel Falcou's answer is great for the older standard but C++11's
parameter packs often make boost type sequences obsolete. Furthermore I think piggy backing templates is better in this case than using boost::lambda
.
Actually my solution uses no includes at all except the Cartesian product template which I will take from here as it is not in the standard library.
Using the currently newest features (as of C++11) allows coding a solution that:
- Scales better.
- Is shorter
- Is more readable because the solution separates the concerns.
The different templates explained:
expand_pack
executes its parameters. This allowes to repeat runtime code using ellipsis. Example: expand_pack(new T{}...)
. Anyone knows the name of this idiom?
wrap_template_as_type
piggy backs a template so it can be used where a type is expected. Maybe this idiom is called template rebinding or late template binding.
I do not know so I posted this question here. Examples: wrap_template_as_type<map>
and the opposite wrapper::unwrapp<int, string>
type_list
a tuple without data, bells and wissels.
template_list
a template that takes a list of templates and returns a type_list with the original templates piggy backed in a wrapper.
make_host_type
converts A, B, C, D
into A<B<C<D>>>
all_hosts
gets a tuple of Host types and news one Host for each element in the input tuple.
Full Example
Note that #include http://...
must be replaced with the linked content
Note that MSVC does not understand PRETTY_FUNCTION but FUNCDNAME I think
#include <iostream>
#include <typeinfo>
#include https://mcmap.net/q/536756/-how-to-create-the-cartesian-product-of-a-type-list
template<typename... Ts> void expand_pack (Ts... t) {}
template <template<typename...> class T>
struct wrapp_template_as_type {
template <typename... Us> using unwrapp = T <Us...>;
};
template<typename... T> struct type_list {};
template <template<typename...> class... Ts>
struct template_list {
using type = type_list< wrapp_template_as_type<Ts>... >;
};
struct TraitA{}; struct TraitB{}; struct TraitC{}; struct TraitD{}; struct TraitE{}; struct TraitF{};
template<typename Trait> struct WhateverA{};
template<typename Trait> struct WhateverB{};
template<typename Whatever> struct FunctionalityA{};
template<typename Whatever> struct FunctionalityB{};
template<typename Whatever> struct FunctionalityC{};
template<typename Whatever> struct FunctionalityD{};
template<typename Func> struct FuncUserA{};
template<typename Func> struct FuncUserB{};
template<typename Func> struct FuncUserC{};
template<typename FuncUser> struct Host { Host() {std::cout << __PRETTY_FUNCTION__ << std::endl;}};
template<typename T> struct make_host_type;
template<template<typename...> class List, typename T, typename... Ts>
struct make_host_type < List<T, Ts...> > {
using type = typename T::template unwrapp < typename make_host_type< List<Ts...> >::type >;
};
template<template<typename...> class List, typename T>
struct make_host_type < List<T> > {
using type = T;
};
template <typename T> struct all_hosts;
template <template<typename...> class Hosts, typename... Ts>
struct all_hosts <Hosts<Ts...> > {
static void create () {
expand_pack (new typename make_host_type<Ts>::type{}...);
}
};
int main () {
using a = type_list < TraitA, TraitB, TraitC, TraitD, TraitE, TraitF >;
using b = typename template_list < WhateverA, WhateverB>::type;
using c = typename template_list < FunctionalityA, FunctionalityB, FunctionalityC, FunctionalityD >::type;
using d = typename template_list < FuncUserA, FuncUserB, FuncUserC >::type;
using e = typename template_list < Host >::type;
using p = typename product<type_list, e, d, c, b, a>::type; // create a type_list of all possible Host types.
all_hosts<p>::create(); // calls constructor for each Host type
}
Output is: (If you use MSVC replace PRETTY_FUNCTION with something else)
Host<FuncUser>::Host() [with FuncUser = FuncUserC<FunctionalityD<WhateverB<TraitF> > >]
Host<FuncUser>::Host() [with FuncUser = FuncUserB<FunctionalityD<WhateverB<TraitF> > >]
Host<FuncUser>::Host() [with FuncUser = FuncUserA<FunctionalityD<WhateverB<TraitF> > >]
Host<FuncUser>::Host() [with FuncUser = FuncUserC<FunctionalityC<WhateverB<TraitF> > >]
Host<FuncUser>::Host() [with FuncUser = FuncUserB<FunctionalityC<WhateverB<TraitF> > >]
Host<FuncUser>::Host() [with FuncUser = FuncUserA<FunctionalityC<WhateverB<TraitF> > >]
Host<FuncUser>::Host() [with FuncUser = FuncUserC<FunctionalityB<WhateverB<TraitF> > >]
Host<FuncUser>::Host() [with FuncUser = FuncUserB<FunctionalityB<WhateverB<TraitF> > >]
...
Host<FuncUser>::Host() [with FuncUser = FuncUserA<FunctionalityA<WhateverA<TraitA> > >]
getHost<5>()
and get the typeHost5_t
. I just want to get rid of the typedefs for all the hosts. Becaues I have far more than in the example and I am afraid at the end of the project there will be even more. – Limitative