5

Tamsayı parametresine sahip bir şablonum var, ancak temel şablon bu gibi static_assert() tarafından devre dışı bırakıldı. (Sadece bazı belirli uzmanlık formlarını istiyorum; ben şablona geçti Herhangi bir bağımsız değişken belirli argümanlar dışında yasaklanacaktır istiyorum) Ben de sık sık ekleyebilir veya bazılarını silin (gibi bu şablon için oluşturan bir kaç uzmanlık varC++ Kısmi uzmanlıklara göre std :: tuple türü nasıl oluşturulur?

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

onları)

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

Şimdi mevcut tüm türlerine göre sadece bir sıfırlanır bir std::tuple oluşturmak istiyorum. Yukarıdaki örnekte, ItemTemplate<1> ve ItemTemplate<2>, ancak ItemTemplate<3> ve diğer uzman olmayan türler. Bunu nasıl başarabilirim?

+0

'ItemID' nedir?ItemTemplate <-1> 'gibi görünüyor, statik iddiayı tetiklemez. Bir [mcve] burada yararlı olur. –

+0

Bu std :: uint32, ve ben bu nokta @Sam Varshavchik –

+0

Hayır olduğunu sanmıyorum, tam olarak bu noktada. Bir 'ItemId ',' std :: tuple , ItemTemplate <5>> 'için bir imzasız hata, bir statik hataya çarptığından bir derleme hatası atar. Sorunuz açık değil. Sorunuz, tüm mevcut uzmanlıkların otomatik olarak nasıl numaralandırılacağıyla ilgili ise, bu C++'da mümkün değildir. Bunu kendiniz açıkça uygulamak zorunda kalacaksınız. –

cevap

2

Sana static_assert() inkar yolunu unutup ItemTemplate ait sadece uzmanlık tanımlamak yalnızca bir şekilde görmek ama. Aşağıdakiler, yalnızca foo bazı uzmanlıklarını tanımladığım ve foo genel yapısının tanımlanmamış kaldığı basitleştirilmiş bir örnektir.

template <std::size_t> 
struct foo; 

template <> struct foo<2U> {}; 
template <> struct foo<3U> {}; 
template <> struct foo<5U> {}; 
template <> struct foo<7U> {}; 

Artık bir tür tanımlanıp tanımlanmadığını tespit etmek için bir şeye ihtiyacınız var; exist<foo<0>>::value sizi false almak ve exist<foo<2>>::value sizi true olsun: Örneğin gereği,

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)); 

aşağıdaki.

Artık bir alt sınıra (örneğin sıfır) bir üst sınıra tanımlanan foo uzmanlık indekslerinin bir listesini (kullanılabilir derleme süresi) kullanmanız gerekir.

için

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; }; 

(sıfırdan bir üst limit) gibi tanımlanmıştır foo çok basit her bir std::tuple elde edilmesi, fooIndexList kullanılması ile elde edilebilir: Örnekte

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 {}); } 

Üst sınır 100'dir, ancak makeFooTuple() şablon parametresi olabilir.

aşağıdaki

#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>>>{}, "!"); 
} 

Sınırları tam derleme örnektir: jenerik foo tanımlı değilse

  • bu çözüm sadece çalışır
  • kodudur C++ 14; C++ 11'de ihtiyacınız varsa, makeFooTuple() numaralı telefonun üst sınırı makeFooTuple() üst sınırında çok daha karmaşık olamaz, çünkü fooIndexList tekrarlayıcıdır, bu nedenle derleyicinin yineleme sınırı tarafından sınırlanır; Bu sınırı atlayabilir, ancak mod kodunu girebilirsiniz.