Std क्यों नहीं है :: C ++ 20 से पहले चिह्नित कॉन्स्ट्रेक्स स्वैप करें?


14

C ++ 20 में, std::swapएक constexprफ़ंक्शन बन जाता है ।

मुझे पता है कि मानक पुस्तकालय वास्तव में चीजों को चिह्नित करने में भाषा से पिछड़ गया था constexpr, लेकिन 2017 तक, <algorithm>अन्य चीजों के एक समूह के रूप में बहुत अधिक बाधा थी। फिर भी - std::swapनहीं था। मुझे अस्पष्ट रूप से याद है कि कुछ अजीब भाषा दोष है जो उस अंकन को रोकते हैं, लेकिन मैं विवरणों को भूल जाता हूं।

क्या कोई इसे स्पष्ट और स्पष्ट रूप से समझा सकता है?

प्रेरणा: यह समझने की आवश्यकता है कि C ++ 11 / C ++ 14 कोड में एक समान std::swap()फ़ंक्शन को चिह्नित करना बुरा क्यों हो सकता है constexpr

जवाबों:


11

विचित्र भाषा का मुद्दा CWG 1581 है :

खण्ड 15 [विशेष] पूरी तरह से स्पष्ट है कि विशेष सदस्य कार्य केवल स्पष्ट रूप से परिभाषित होते हैं जब वे ओड-उपयोग किए जाते हैं। यह अविकसित संदर्भों में निरंतर अभिव्यक्तियों के लिए एक समस्या पैदा करता है:

struct duration {
  constexpr duration() {}
  constexpr operator int() const { return 0; }
};

// duration d = duration(); // #1
int n = sizeof(short{duration(duration())});

यहां मुद्दा यह है कि हमें constexpr duration::duration(duration&&)इस कार्यक्रम में स्पष्ट रूप से परिभाषित करने की अनुमति नहीं है , इसलिए इनिशियलज़र सूची में अभिव्यक्ति एक स्थिर अभिव्यक्ति नहीं है (क्योंकि यह एक कॉन्स्ट्रेक्स फ़ंक्शन को परिभाषित करता है जिसे परिभाषित नहीं किया गया है), इसलिए ब्रेडेड इनिशियलाइज़र में एक संकीर्ण रूपांतरण होता है , इसलिए कार्यक्रम बीमार है।

यदि हम लाइन # 1 को अनकंफर्ट करते हैं, तो मूव कंस्ट्रक्टर को स्पष्ट रूप से परिभाषित किया जाता है और प्रोग्राम मान्य होता है। दूरी पर यह डरावना कार्रवाई बेहद दुर्भाग्यपूर्ण है। कार्यान्वयन इस बिंदु पर विचलन करते हैं।

आप मुद्दे के बाकी विवरण पढ़ सकते हैं।

2017 में अल्बुकर्क में P0859 में इस मुद्दे के लिए एक संकल्प अपनाया गया था (C ++ 17 के बाद)। यह समस्या दोनों के लिए एक अवरोधक थी constexpr std::swap( P0879 में हल किया गया ) और P1065constexpr std::invoke में हल किया गया ( जिसमें CWG1581 उदाहरण भी हैं) दोनों, C ++ 20 के लिए दोनों के लिए एक अवरोधक थे ।


उदाहरण को समझने के लिए सबसे सरल, मेरी राय में, एलएलवीएम बग रिपोर्ट से कोड P1065 में बताया गया है:

template<typename T>
int f(T x)
{
    return x.get();
}

template<typename T>
constexpr int g(T x)
{
    return x.get();
}

int main() {

  // O.K. The body of `f' is not required.
  decltype(f(0)) a;

  // Seems to instantiate the body of `g'
  // and results in an error.
  decltype(g(0)) b;

  return 0;
}

CWG1581 सभी के बारे में है जब कॉन्स्टैक्स सदस्य के कार्य परिभाषित किए गए हैं, और संकल्प यह सुनिश्चित करता है कि वे केवल तब ही परिभाषित किए जाते हैं जब उपयोग किया जाता है। P0859 के बाद, ऊपर अच्छी तरह से गठित (प्रकार bहै int)।

के बाद से std::swapऔर std::invokeदोनों सदस्य कार्यों के लिए जाँच (पूर्व में कदम निर्माण / असाइनमेंट और कॉल ऑपरेटर / बाद में किराए की कॉल), वे दोनों इस मुद्दे के समाधान पर निर्भर पर भरोसा करने के लिए है।


तो, CWG-1581 एक स्वैप फ़ंक्शन को कॉन्स्टैक्स के रूप में चिह्नित करने के लिए अवांछनीय क्यों रोकता है / बनाता है?
ईनपोकलम

3
@einpoklum स्वैप की आवश्यकता std::is_move_constructible_v<T> && std::is_move_assignable_v<T>है true। ऐसा नहीं हो सकता है यदि विशेष सदस्य कार्य अभी तक उत्पन्न नहीं हुए हैं।
नेथनऑलिवर

@NathanOliver: इसे मेरे उत्तर में जोड़ा गया।
ईनपोकलम

5

कारण

(@NathanOliver के कारण)

constexprस्वैप फंक्शन की अनुमति देने के लिए , आपको इस फंक्शन के लिए टेम्प्लेट करने से पहले यह जाँचना होगा - कि स्वैप किया गया मूव-कंस्ट्रक्टिव और मूव-असाइन है। दुर्भाग्यवश, केवल C ++ 20 में हल की गई भाषा की खराबी के कारण, आप उसके लिए जांच नहीं कर सकते हैं , क्योंकि संबंधित सदस्य फ़ंक्शन अभी तक परिभाषित नहीं किए गए हैं, जहां तक ​​संकलक का संबंध है।

कालक्रम

  • 2016: एंटनी Polukhin submitts प्रस्ताव P0202 , के सभी चिह्नित करने के लिए <algorithm>के रूप में कार्य constexpr
  • मानक समिति का मुख्य कार्यकारी समूह सीडब्ल्यूजी -1581 दोष की चर्चा करता है । इस समस्या ने इसे constexpr std::swap()और भी समस्याग्रस्त बना दिया constexpr std::invoke()- ऊपर स्पष्टीकरण देखें।
  • 2017: एंटनी ने कुछ std::swapऔर निर्माणों को बाहर करने के लिए अपने प्रस्ताव को कुछ बार संशोधित किया और इसे C ++ 17 में स्वीकार किया गया।
  • 2017: CWG-1581 के लिए एक प्रस्ताव P0859 के रूप में प्रस्तुत किया गया है और 2017 में मानक समिति द्वारा स्वीकार किया गया है (लेकिन C ++ 17 के बाद भेज दिया गया है)।
  • 2017 का अंत: एंटनी CWG-1581 के संकल्प के बाद बाधा बनाने के लिए एक पूरक प्रस्ताव, P0879 को प्रस्तुत करता है std::swap()
  • 2018: पूरक प्रस्ताव C ++ 20 में स्वीकार किया जाता है (?)। जैसा कि बैरी बताते हैं, इसलिए कॉन्स्टैक्स std::invoke()फिक्स है।

आपका विशिष्ट मामला

constexprयदि आप मूव-कंस्ट्रक्शन और मूव-असाइन करने की जांच नहीं करते हैं, तो आप स्वैपिंग का उपयोग कर सकते हैं , बल्कि सीधे कुछ अन्य प्रकार की विशेषताओं की जांच कर सकते हैं, जो विशेष रूप से सुनिश्चित करती हैं। उदाहरण के लिए केवल आदिम प्रकार और कोई वर्ग या संरचना नहीं। या, सैद्धांतिक रूप से, आप चेक को वापस ले सकते हैं और बस आपके द्वारा सामना की जा सकने वाली किसी भी संकलन त्रुटियों से निपट सकते हैं, और संकलक के साथ परतदार व्यवहार के साथ। किसी भी मामले में, std::swap()उस तरह की चीज़ से प्रतिस्थापित न करें ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.