I see a way, but only if you forget the static_assert() failure method and define only ItemTemplate specializations.
The following is a simplified example in which I define only some specializations of foo , and the general structure of foo remains undefined.
template <std::size_t> struct foo; template <> struct foo<2U> {}; template <> struct foo<3U> {}; template <> struct foo<5U> {}; template <> struct foo<7U> {};
Now you need to determine something if the type is defined or not; for example next
template <typename T, std::size_t = sizeof(T)> std::true_type existH (int); template <typename> std::false_type existH (long); template <typename T> using exist = decltype(existH<T>(0));
That is: from exist<foo<0>>::value you get false and from exist<foo<2>>::value get true .
Now you need a list (compilation time) of the specialization indices foo , defined from the lower limit (zero, for example) to the upper limit.
You can get it with
template <std::size_t I, std::size_t topI, typename, bool = (I == topI) || exist<foo<I>>::value> struct fooIndexList; template <std::size_t topI, std::size_t ... Ixs> struct fooIndexList<topI, topI, std::index_sequence<Ixs...>, true> { using type = std::index_sequence<Ixs...>; }; template <std::size_t I, std::size_t topI, std::size_t ... Ixs> struct fooIndexList<I, topI, std::index_sequence<Ixs...>, true> { using type = typename fooIndexList<I+1U, topI, std::index_sequence<Ixs..., I>>::type; }; template <std::size_t I, std::size_t topI, std::size_t ... Ixs> struct fooIndexList<I, topI, std::index_sequence<Ixs...>, false> { using type = typename fooIndexList<I+1U, topI, std::index_sequence<Ixs...>>::type; };
Using fooIndexList , getting a std::tuple with all foo set (from zero to the upper limit) is very simple:
template <std::size_t ... Idx> constexpr auto makeFooTupleH (std::index_sequence<Idx...> const &) { return std::make_tuple( foo<Idx>{} ... ); } constexpr auto makeFooTuple () { return makeFooTupleH( typename fooIndexList<0U, 100U, std::index_sequence<>>::type {}); }
In the example, the upper limit is 100 , but it can be a makeFooTuple() template parameter.
Below is a complete compilation example
#include <tuple> #include <utility> #include <iostream> #include <type_traits> template <typename T, std::size_t = sizeof(T)> std::true_type existH (int); template <typename> std::false_type existH (long); template <typename T> using exist = decltype(existH<T>(0)); template <std::size_t> struct foo; template <> struct foo<2U> {}; template <> struct foo<3U> {}; template <> struct foo<5U> {}; template <> struct foo<7U> {}; template <std::size_t I, std::size_t topI, typename, bool = (I == topI) || exist<foo<I>>::value> struct fooIndexList; template <std::size_t topI, std::size_t ... Ixs> struct fooIndexList<topI, topI, std::index_sequence<Ixs...>, true> { using type = std::index_sequence<Ixs...>; }; template <std::size_t I, std::size_t topI, std::size_t ... Ixs> struct fooIndexList<I, topI, std::index_sequence<Ixs...>, true> { using type = typename fooIndexList<I+1U, topI, std::index_sequence<Ixs..., I>>::type; }; template <std::size_t I, std::size_t topI, std::size_t ... Ixs> struct fooIndexList<I, topI, std::index_sequence<Ixs...>, false> { using type = typename fooIndexList<I+1U, topI, std::index_sequence<Ixs...>>::type; }; template <std::size_t ... Idx> constexpr auto makeFooTupleH (std::index_sequence<Idx...> const &) { return std::make_tuple( foo<Idx>{} ... ); } constexpr auto makeFooTuple () { return makeFooTupleH( typename fooIndexList<0U, 100U, std::index_sequence<>>::type {}); } int main () { auto ft = makeFooTuple(); static_assert( std::is_same<decltype(ft), std::tuple<foo<2U>, foo<3U>, foo<5U>, foo<7U>>>{}, "!"); }
Limitations:
- this solution only works if generic
foo not defined - C ++ 14 code; if you need it in C ++ 11, this is a little more complicated.
- the upper limit in
makeFooTuple() cannot be a large number, because fooIndexList is recursive, so the compiler recursion limit limits it; you can get around this limit, but a mode code is required.