Je vois une façon, mais seulement si vous oubliez le chemin de refus static_assert()
et de définir seulement les spécialisations de ItemTemplate
.
Voici un exemple simplifié où je ne définis que certaines spécialisations de foo
et la structure générique foo
reste indéfinie.
template <std::size_t>
struct foo;
template <> struct foo<2U> {};
template <> struct foo<3U> {};
template <> struct foo<5U> {};
template <> struct foo<7U> {};
Vous avez maintenant besoin de quelque chose à détecter si un type est défini ou non; par exemple, les éléments suivants
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));
qui est: de exist<foo<0>>::value
vous false
et de exist<foo<2>>::value
vous obtenez true
.
Maintenant, vous avez besoin d'une liste (temps de compilation utilisable) des index de foo
spécialisation définie à partir d'une limite inférieure (zéro, par exemple) à une limite supérieure.
Vous pouvez l'obtenir avec
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; };
En utilisant fooIndexList
, l'obtention d'un std::tuple
avec tous les foo
défini (de zéro à une limite supérieure) est très 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 {}); }
Dans l'exemple, La limite supérieure est 100
mais peut être un paramètre de modèle de makeFooTuple()
.
Voici un exemple complet compilation
#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>>>{}, "!");
}
Limites:
- cette solution ne fonctionne que si le
foo
générique ne
- le code est 14 C++; si vous en avez besoin en C++ 11 c'est un peu plus compliqué
- la limite supérieure en
makeFooTuple()
ne peut pas être un grand nombre car fooIndexList
est récursif donc est limité par la limite de récursivité du compilateur; Vous pouvez contourner cette limite mais exiger un code de mode.
Qu'est-ce que "ItemID"?On dirait que 'ItemTemplate <-1>' ne déclencherait pas l'assertion statique. Un [mcve] serait utile ici. –
C'est std :: uint32, et je ne pense pas que ce soit le point @Sam Varshavchik –
Non, c'est exactement le point. En utilisant un 'unfigned int' pour un' ItemId', 'std :: tuple, ItemTemplate <5>>' déclenche une erreur de compilation, car il frappe évidemment l'assertion statique. Votre question n'est pas claire. Si votre question concerne vraiment l'énumération automatique de toutes les spécialisations disponibles, cela n'est pas possible en C++. Vous devrez l'implémenter explicitement vous-même. –