5

मेरे पास एक पूर्णांक पैरामीटर वाला टेम्पलेट है, लेकिन आधार टेम्पलेट static_assert() द्वारा इस तरह अक्षम किया गया है। (मैं केवल कुछ निश्चित विशेषज्ञता रूपों चाहते हैं, मैं चाहता हूँ किसी भी तर्क टेम्पलेट के लिए पारित कुछ तर्कों के अलावा प्रतिबंधित किया जा करने के लिए)सी ++ आंशिक विशेषज्ञता के आधार पर std :: tuple प्रकार कैसे बनाएं?

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

मैं भी कई विशेषज्ञताओं है की तरह (मैं अक्सर जोड़ सकते हैं या में से कुछ को हटाने के इस टेम्पलेट के लिए फार्म उन्हें)

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

अब मैं एक std::tuple जो सभी उपलब्ध प्रकार से केवल initialised है बनाना चाहते हैं। तो उपर्युक्त उदाहरण में, ItemTemplate<1> और ItemTemplate<2>, लेकिन ItemTemplate<3> और अन्य गैर-विशिष्ट प्रकार नहीं। मुझे यह कैसे हासिल होगा?

+0

'ItemID' क्या है?ऐसा लगता है कि 'ItemTemplate <-1>' स्थिर स्थिरता को ट्रिगर नहीं करेगा। एक [एमसीवी] यहां उपयोगी होगा। –

+0

यह std :: uint32 है, और मुझे नहीं लगता कि यह बिंदु @ सैम वरशाविक –

+0

नहीं है, यह बिल्कुल सही बात है। 'ItemId' के लिए 'हस्ताक्षरित int' का उपयोग करके,' std :: tuple , ItemTemplate <5>> 'संकलन त्रुटि फेंकता है, क्योंकि यह स्पष्ट रूप से स्थैतिक जोर देता है। आपका सवाल अस्पष्ट है। यदि आपका प्रश्न वास्तव में सभी उपलब्ध विशेषज्ञताओं को स्वचालित रूप से कैसे समझाता है, तो यह C++ में संभव नहीं है। आपको इसे स्वयं स्पष्ट रूप से लागू करना होगा। –

उत्तर

2

मैं एक तरह से देखते हैं लेकिन इसके लिए आपको static_assert() इनकार रास्ता भूल जाते हैं और केवलItemTemplate की विशेषज्ञताओं परिभाषित करते हैं।

निम्नलिखित एक सरलीकृत उदाहरण है जहां मैं केवल foo की कुछ विशेषताओं को परिभाषित करता हूं और foo सामान्य संरचना अपरिभाषित रहती है।

template <std::size_t> 
struct foo; 

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

अब आपको यह पता लगाने के लिए कुछ चाहिए कि कोई प्रकार परिभाषित किया गया है या नहीं; exist<foo<0>>::value से आप false हो और exist<foo<2>>::value से आप true मिलती है: उदाहरण के द्वारा,

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

यही कारण है निम्नलिखित।

अब आपको foo की इंडेक्स की एक सूची (उपयोग योग्य संकलन समय) की निचली सीमा (शून्य, उदाहरण के अनुसार) से ऊपरी सीमा तक परिभाषित विशेषज्ञता की आवश्यकता है।

आप इसे

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

fooIndexList का उपयोग करना, सभी foo (शून्य से एक ऊपरी सीमा के लिए) परिभाषित बहुत सरल है के साथ एक std::tuple प्राप्त करने के साथ प्राप्त कर सकते हैं:

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

उदाहरण में ऊपरी सीमा 100 है लेकिन makeFooTuple() का टेम्पलेट पैरामीटर हो सकता है।

निम्नलिखित एक पूर्ण संकलन उदाहरण

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

सीमा है:

  • इस समाधान तभी काम करता है सामान्य foo परिभाषित नहीं है
  • कोड है सी ++ 14; यदि आपको सी ++ 11 में इसकी आवश्यकता है तो यह थोड़ा और जटिल है
  • makeFooTuple() में ऊपरी सीमा बड़ी संख्या नहीं हो सकती है क्योंकि fooIndexList रिकर्सिव है इसलिए संकलक की रिकर्सन सीमा से सीमित है; आप इस सीमा को बाईपास कर सकते हैं लेकिन मोड कोड की आवश्यकता है।
संबंधित मुद्दे