I see a way but only if you forget the static_assert() denial way and define only the specializations of ItemTemplate.
The following is a simplified example where I define only some specializations of foo and the foo generic struct remain 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 something to detect if a type is defined or not; by example, the following
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 you get true.
Now you need a list (usable compile time) of indexes of foo specialization defined from a lower limit (zero, by example) to an upper limit.
You can obtain 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, obtaining a std::tuple with all the foo defined (from zero to an 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 can be a template parameter of makeFooTuple().
The following is a full compiling 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>>>{}, "!");
}
Limits:
- this solution works only if the generic
foo isn't defined
- the code is C++14; if you need it in C++11 it's a little more complicated
- the upper limit in
makeFooTuple() can't be a big number because fooIndexList is recursive so is limited by the compiler's recursion limit; you can bypass this limit but require mode code.