2015-01-27 11 views
8

क्या यह जांचना संभव है कि टेम्पलेट प्रकार को संकलित समय पर तत्काल किया गया है ताकि मैं इस जानकारी का उपयोग enable_if विशेषज्ञता में कर सकूं?संकलित समय टेम्पलेट तत्काल जांच

मान लीजिए कि मैं

template <typename T> struct known_type { }; 

मैं किसी भी तरह कुछ is_known_type जिसका मूल्य अगर known_type संकलन समय पर instantiated है सच है परिभाषित कर सकता हूँ करते हैं?

+0

आपको एक उदाहरण एक enable_if में इस प्रकार की जानकारी का उपयोग कर दिखाने के कर सकते हैं? – erenon

+0

स्वीकार्य उत्तर नए कंपाइलरों पर काम नहीं करता है। ऐसा लगता है कि उत्तर कुछ जीसीसी कंपाइलर बग पर निर्भर करता है और समाधान मानक अनुरूप कंपिलरों पर काम नहीं करता है। –

उत्तर

15

यदि आप इस तथ्य का लाभ उठाते हैं कि विशिष्ट अभिव्यक्तियों का उपयोग constexpr एस की अपेक्षा की जा सकती है, तो यह संभव है कि आप यह सुनिश्चित कर सकें कि आपके प्रत्येक उम्मीदवार के लिए राज्य क्या है। विशेष रूप से हमारे मामले में, तथ्य यह है कि constexpr एस बिना किसी परिभाषा के निरंतर अभिव्यक्ति के रूप में पारित नहीं हो सकता है और noexcept निरंतर अभिव्यक्तियों की गारंटी है। इसलिए, noexcept(...)true लौटने से ठीक से परिभाषित constexpr की उपस्थिति का संकेत मिलता है।

अनिवार्य रूप से, यह constexpr एस को हां/नहीं स्विच के रूप में मानता है, और संकलन समय पर राज्य प्रस्तुत करता है।

ध्यान दें कि यह बहुत हैक है, आपको विशिष्ट कंपाइलर्स के लिए वर्कअराउंड की आवश्यकता होगी (आगे के लेख देखें) और यह विशिष्ट friend-आधारित कार्यान्वयन मानक के भविष्य के संशोधन से बीमार गठित माना जा सकता है।

कि रास्ते से बाहर के साथ

...

उपयोगकर्ता Filip Roséen विशेष रूप से यह करने के लिए समर्पित his article में इस अवधारणा प्रस्तुत करता है।

उसका उदाहरण दिया गया है, उद्धृत स्पष्टीकरण के साथ:

constexpr int flag (int); 

एक constexpr समारोह में दोनों में से कोई या तो हो सकता है; या तो यह निरंतर अभिव्यक्ति में प्रयोग योग्य है, या यह नहीं है - यदि इसमें परिभाषा की कमी है तो यह स्वचालित रूप से बाद की श्रेणी में आती है - अन्य राज्य नहीं है (जब तक कि हम अपरिभाषित व्यवहार पर विचार नहीं करते)।

आम तौर पर, कॉन्सएक्सप्रैक्ट फ़ंक्शंस का बिल्कुल ठीक व्यवहार किया जाना चाहिए जैसा कि वे हैं; फ़ंक्शंस, लेकिन हम उन्हें "वेरिएबल्स" के लिए अलग-अलग हैंडल के रूप में भी सोच सकते हैं, जिसमें बूल के समान प्रकार होता है, जहां प्रत्येक "चर" में दो मानों में से एक हो सकता है; प्रयोग योग्य या उपयोग करने योग्य नहीं।

हमारे कार्यक्रम में यदि आप ध्वज को केवल उस पर विचार करते हैं तो यह मदद करता है; एक हैंडल (फ़ंक्शन नहीं)। इसका कारण यह है कि हम कभी भी मूल्यांकन संदर्भ में ध्वज को कभी भी कॉल नहीं करेंगे, हम केवल अपनी वर्तमान स्थिति में रूचि रखते हैं।

template<class Tag> 
struct writer { 
    friend constexpr int flag (Tag) { 
    return 0; 
    } 
}; 

लेखक एक वर्ग टेम्पलेट जो, इन्स्टेन्शियशन पर, उसके आसपास के नाम स्थान ( हस्ताक्षर पूर्णांक झंडा होने (टैग), में एक समारोह जहां टैग एक टेम्पलेट है के लिए एक परिभाषा बनाएगा है पैरामीटर)।

यदि हम एक बार फिर constexpr कार्यों के बारे में सोच के रूप में कुछ चर को संभालती है, हम दोस्त-घोषणा में समारोह के पीछे चर करने के लिए प्रयोग करने योग्य मूल्य का एक बिना शर्त लिखने के रूप में लेखक की एक इन्स्टेन्शियशन इलाज कर सकते हैं।

template<bool B, class Tag = int> 
struct dependent_writer : writer<Tag> { }; 

मैं हैरान अगर आपको लगता है dependent_writer एक बल्कि व्यर्थ अविवेक की तरह दिखता है नहीं होगा, लेखक को तुरंत क्यों न करें, जहां हम इसका उपयोग करना चाहते हैं, dependent_writer के माध्यम से जाने के बजाय?

  1. लेखक के तत्काल तत्काल तत्कालता को रोकने के लिए कुछ पर निर्भर होना चाहिए, और;
  2. dependent_writer का उपयोग उस संदर्भ में किया जाता है जहां प्रकार के बूल का मूल्य निर्भरता के रूप में उपयोग किया जा सकता है।
template< 
    bool B = noexcept (flag (0)), 
    int = sizeof (dependent_writer<B>) 
> 
constexpr int f() { 
    return B; 
} 

ऊपर एक छोटे से अजीब लग सकता है, लेकिन यह वास्तव में बहुत सरल है,

  1. बी = सत्य सेट करेगा यदि ध्वज (0) स्थिर अभिव्यक्ति है, अन्यथा बी = झूठी, और;
  2. निहित रूप से dependent_writer को तत्काल करता है (आकार के लिए एक पूर्ण परिभाषित प्रकार की आवश्यकता होती है)।

    IF [ `int flag (int)` has not yet been defined ]: 
        SET `B` = `false` 
        INSTANTIATE `dependent_writer<false>` 
        RETURN  `false` 
    ELSE: 
        SET `B` = `true` 
        INSTANTIATE `dependent_writer<true>` 
        RETURN  `true` 
    

अंत में, अवधारणा के सबूत:

int main() { 
    constexpr int a = f(); 
    constexpr int b = f(); 
    static_assert (a != b, "fail"); 
} 

मैं अपने विशेष को यह लागू किया

व्यवहार निम्नलिखित छद्म कोड के साथ व्यक्त किया जा सकता मुसीबत। विचार constexpr हां/नहीं स्विच का उपयोग यह इंगित करने के लिए है कि एक प्रकार को तत्काल किया गया है या नहीं। इसलिए, आपको अपने पास हर प्रकार के लिए एक अलग स्विच की आवश्यकता होगी।

template<typename T> 
struct inst_check_wrapper 
{ 
    friend constexpr int inst_flag(inst_check_wrapper<T>); 
}; 

inst_check_wrapper<T> अनिवार्य रूप से जो कुछ भी प्रकार आप इसे दे सकता है के लिए एक स्विच गिर्द घूमती है। यह मूल उदाहरण का सिर्फ एक सामान्य संस्करण है।

template<typename T> 
struct writer 
{ 
    friend constexpr int inst_flag(inst_check_wrapper<T>) 
    { 
     return 0; 
    } 
}; 

स्विच टॉगलर मूल उदाहरण में से एक के समान है। यह आपके द्वारा उपयोग किए जाने वाले कुछ प्रकार के स्विच की परिभाषा के साथ आता है।आसान जांच के लिए अनुमति देने के लिए, एक सहायक स्विच इंस्पेक्टर जोड़ें:

template <typename T, bool B = noexcept(inst_flag(inst_check_wrapper<T>()))> 
constexpr bool is_instantiated() 
{ 
    return B; 
} 

अंत में, प्रकार "रजिस्ट्रार" स्वयं प्रारंभ के रूप में। मेरे मामले में:

template <typename T> 
struct MyStruct 
{ 
    template <typename T1 = T, int = sizeof(writer<MyStruct<T1>>)> 
    MyStruct() 
    {} 
}; 

जैसे ही उस विशेष निर्माता के लिए पूछा जाता है, स्विच चालू हो जाता है। नमूना:

int main() 
{ 
    static_assert(!is_instantiated<MyStruct<int>>(), "failure"); 
    MyStruct<int> a; 
    static_assert(is_instantiated<MyStruct<int>>(), "failure"); 
} 

Live on Coliru.

+0

लिख रहा हूं, मुझे डर है, यह काम नहीं करेगा एकाधिक अनुवाद इकाइयां। –

+0

क्या यह "ब्लैक जादू" का मतलब है? –

+1

@GuillaumeRacicot यह टेम्पलेटमेंसी है। –

-1

ऐसा करने का कोई तरीका नहीं है। तो मैं कहूंगा: सं।

2

नहीं, तत्काल कक्षाओं के लिए संकलन समय की जांच संभव नहीं है। हालांकि आप तत्काल कक्षाओं (डीबग बिल्ड में) का एक (स्थैतिक) मानचित्र स्थापित कर सकते हैं, जिसे आप रन टाइम पर देख सकते हैं।

हालांकि, वास्तव में तत्काल कक्षाओं के साथ अपेक्षित तत्काल कक्षाओं की एक सूची की तुलना करके लिंक्ड बाइनरी का विश्लेषण करना संभव होना चाहिए (लेकिन यह पिछले संकलन समय और मेरे ज्ञान से पहले है)।

+0

मेरी समस्या एक संरचना के आंशिक विशेषज्ञता को ओवरलैप करने में हल हो रही है, मेरे पास एक विशेषज्ञता है जिसे केवल ज्ञात प्रकारों के लिए लागू किया जाना चाहिए जो संकलित समय तक वास्तव में ज्ञात नहीं हैं क्योंकि यह एक टेम्पलेट लाइब्रेरी है, मैं – tuccio

संबंधित मुद्दे