यदि आप इस तथ्य का लाभ उठाते हैं कि विशिष्ट अभिव्यक्तियों का उपयोग 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 के माध्यम से जाने के बजाय?
- लेखक के तत्काल तत्काल तत्कालता को रोकने के लिए कुछ पर निर्भर होना चाहिए, और;
- dependent_writer का उपयोग उस संदर्भ में किया जाता है जहां प्रकार के बूल का मूल्य निर्भरता के रूप में उपयोग किया जा सकता है।
template<
bool B = noexcept (flag (0)),
int = sizeof (dependent_writer<B>)
>
constexpr int f() {
return B;
}
ऊपर एक छोटे से अजीब लग सकता है, लेकिन यह वास्तव में बहुत सरल है,
- बी = सत्य सेट करेगा यदि ध्वज (0) स्थिर अभिव्यक्ति है, अन्यथा बी = झूठी, और;
- निहित रूप से 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.
आपको एक उदाहरण एक enable_if में इस प्रकार की जानकारी का उपयोग कर दिखाने के कर सकते हैं? – erenon
स्वीकार्य उत्तर नए कंपाइलरों पर काम नहीं करता है। ऐसा लगता है कि उत्तर कुछ जीसीसी कंपाइलर बग पर निर्भर करता है और समाधान मानक अनुरूप कंपिलरों पर काम नहीं करता है। –