5

J'ai un modèle avec un paramètre entier, mais le modèle de base est désactivé par static_assert() comme ceci. (Je veux seulement quelques certaines formes de spécialisation, je veux tout argument passé au modèle interdits à l'exception de certains arguments)C++ Comment faire un type std :: tuple basé sur des spécialisations partielles?

template<ItemID item_id> struct ItemTemplate{ 
    static_assert(item_id == -1,"Cann't use unspecialized ItemTemplate!"); 
    static ItemID id{ std::numeric_limits<ItemID>::max() }; 
    //... 
}; 

J'ai aussi plusieurs spécialisations former pour ce modèle comme (je rajoute souvent ou supprimer certains des les)

template<> struct ItemTemplate<1>{ 
    static constexpr ItemID id{1}; 
    //.. 
}; 
template<> struct ItemTemplate<2>{ 
    static constexpr ItemID id{2}; 
    //... 
}; 

maintenant, je veux créer un std::tuple qui est initialisée que par tous les types disponibles. Donc, dans l'exemple ci-dessus, ItemTemplate<1> et ItemTemplate<2>, mais pas ItemTemplate<3> et d'autres types non spécialisés. Comment puis-je y parvenir?

+0

Qu'est-ce que "ItemID"?On dirait que 'ItemTemplate <-1>' ne déclencherait pas l'assertion statique. Un [mcve] serait utile ici. –

+0

C'est std :: uint32, et je ne pense pas que ce soit le point @Sam Varshavchik –

+0

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. –

Répondre

2

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.