असमानता को C ++ मानक पुस्तकालय कोड के एक बहुत में (- (a = b)) के रूप में क्यों जांचा जाता है?


142

यह C ++ मानक पुस्तकालय removeकोड से कोड है। if (!(*first == val))इसके बजाय असमानता का परीक्षण क्यों किया जाता है if (*first != val)?

 template <class ForwardIterator, class T>
      ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& val)
 {
     ForwardIterator result = first;
     while (first!=last) {
         if (!(*first == val)) {
             *result = *first;
             ++result;
         }
         ++first;
     }
     return result;
 }

2
@ बेलरस्टूडिओस शायद सही है। इसे लागू करते समय भी आम है operator!=। बस operator==कार्यान्वयन का उपयोग करें :bool operator!=(const Foo& other) { return !(*this == other); }
साइमन

1
वास्तव में मैं अपने कथन को सही करता हूं: संदर्भ उल्लेख उन सभी तत्वों को हटा देता है जो मूल्य के बराबर हैं इसलिए operator==यहां इस्तेमाल होने की उम्मीद है ...
BeyelerStudios

ओह, और constमेरी पिछली टिप्पणी में उदाहरण में भी होना चाहिए , लेकिन आपको यह बात मिल गई है। (इसे संपादित करने के लिए बहुत देर हो चुकी है)
सिमोन

इसका कारण एक अन्य प्रश्न से संबंधित है (जो मूल रूप से "नहीं, जरूरी नहीं" के साथ उत्तर दिया जा सकता है), और होने की अवधारणा EqualityComparableजिसे हर्किल ने अपने उत्तर में उल्लेख किया है ।
मार्को 13

जवाबों:


144

क्योंकि इसका मतलब है कि टी पर केवल आवश्यकता एक को लागू करने की है operator==। आपको टी की आवश्यकता हो सकती है, operator!=लेकिन यहां सामान्य विचार यह है कि आपको टेम्प्लेट के उपयोगकर्ता पर यथासंभव कम बोझ डालना चाहिए और अन्य टेम्प्लेट की आवश्यकता है operator==


13
टेम्पलेट <class T> इनलाइन बूल ऑपरेटर! = <T a, T b> {return! (a == b); }
जोशुआ

8
क्या कोई ऐसा परिदृश्य होगा जहां कोई कंपाइलर = के सभी उदाहरणों को इंटरचेंज नहीं कर पाएगा! to (==)? यह पहले से ही संकलक के लिए डिफ़ॉल्ट कार्रवाई क्यों नहीं होगी?
गोमेज़

20
@AidanGomez बेहतर या बदतर के लिए आप ऑपरेटरों को ओवरलोड कर सकते हैं जो आप चाहते हैं। यह समझ में नहीं आता है या सुसंगत नहीं है।
नील कर्क

10
x != yके रूप में ही परिभाषित नहीं किया गया है !(x == y)। क्या होगा अगर ये ऑपरेटर एक एम्बेडेड डीएसएल के पार्स ट्री को वापस कर दें?
ब्राइस एम। डेम्पसे

7
@ जोशुआ बुरी तरह से टूट जाता है अगर यह पता लगाने के लिए कि क्या !=समर्थित है एसएफआईएनईई का उपयोग करने का प्रयास कर रहा है (गलत तरीके से सच लौटाएगा - यदि operator==समर्थित नहीं है!)। मुझे यह भी चिंता है कि यह !=अस्पष्ट होने के कुछ उपयोगों का कारण बनेगा।

36

एसटीएल में अधिकांश कार्य केवल operator<या उसके साथ काम करते हैं operator==। इसके लिए उपयोगकर्ता को केवल इन दो ऑपरेटरों (या कभी-कभी उनमें से कम से कम एक) को लागू करने की आवश्यकता होती है। उदाहरण के लिए std::setउपयोग करता है operator<(अधिक सटीक रूप से std::lessजो operator<डिफ़ॉल्ट रूप से आक्रमण करता है) और operator>ऑर्डर करने का प्रबंधन नहीं करता है । removeअपने उदाहरण में टेम्पलेट एक समान मामला है - यह केवल का उपयोग करता है operator==और नहीं operator!=तो operator!=परिभाषित करने की जरूरत नहीं है।


2
कार्य operator<सीधे उपयोग नहीं करते हैं, बल्कि उपयोग करते हैं std::less, जो बदले में चूक करते हैं operator<
क्रिश्चियन हैकल

1
वास्तव में, ऐसा लगता है कि मानक एल्गोरिथ्म कार्य करता है, उदाहरण के लिए std::set, वास्तव में operator<सीधे उपयोग करते हैं। अजीब बात है ...
क्रिश्चियन Hackl

1
ये फ़ंक्शन उपयोग नहीं करते हैं std::equal_to, वे operator==प्रश्न में नोट किए गए अनुसार उपयोग करते हैं । के साथ स्थिति std::lessसमान है। खैर, शायद std::setसबसे अच्छा उदाहरण नहीं है।
लुका बेदन्ना

2
@ChristianHackl, std::equal_toऔर std::lessडिफ़ॉल्ट टेम्पलेट पैरामीटर के रूप में उपयोग किया जाता है जहां तुलनित्र को पैरामीटर के रूप में लिया जाता है। operator==और operator<सीधे उपयोग किया जाता है जहां प्रकार को क्रमशः तुलनीय और सख्त कमजोर आदेश को संतुष्ट करने की आवश्यकता होती है, जैसे कि पुनरावृत्तियों और यादृच्छिक अभिगम पुनरावृत्तियों।
Jan Hudec

28

यह C ++ मानक लाइब्रेरी रिमूव कोड का कोड है।

गलत। ऐसा नहीं है सी ++ मानक पुस्तकालय कोड। यह C ++ मानक लाइब्रेरी फ़ंक्शन का एक संभावित आंतरिक कार्यान्वयन है । C ++ मानक वास्तविक कोड नहीं लिखता है; यह फ़ंक्शन प्रोटोटाइप और आवश्यक व्यवहार निर्धारित करता है।removeremove

दूसरे शब्दों में: सख्त भाषा के दृष्टिकोण से, जो कोड आप देख रहे हैं वह मौजूद नहीं है । यह कुछ हेडर फ़ाइल से हो सकता है जो आपके संकलक के मानक-पुस्तकालय कार्यान्वयन के साथ आता है। ध्यान दें कि C ++ मानक को उन हेडर फ़ाइलों की आवश्यकता भी नहीं है। फ़ाइलें कंपाइलर कार्यान्वयनकर्ताओं के लिए एक लाइन की आवश्यकताओं को पूरा करने के लिए एक सुविधाजनक तरीका है #include <algorithm>(जैसे कि मेकिंग std::removeऔर अन्य फ़ंक्शन उपलब्ध)।

if (!(*first == val))इसके बजाय असमानता का परीक्षण क्यों किया जाता है if (*first != val)?

क्योंकि केवल operator==फ़ंक्शन द्वारा आवश्यक है।

जब कस्टम प्रकारों के लिए ऑपरेटर ओवरलोडिंग की बात आती है, तो भाषा आपको सभी प्रकार की अजीब चीजें करने की अनुमति देती है। आप बहुत अच्छी तरह से एक वर्ग बना सकते हैं जिसमें एक अतिभारित है operator==लेकिन कोई अतिभारित नहीं है operator!=। या इससे भी बदतर: आप ओवरलोड कर सकते हैं operator!=लेकिन क्या यह पूरी तरह से असंबंधित चीजें हैं।

इस उदाहरण पर विचार करें:

#include <algorithm>
#include <vector>

struct Example
{
    int i;

    Example() : i(0) {}

    bool operator==(Example const& other) const
    {
        return i == other.i;
    }

    bool operator!=(Example const& other) const
    {
        return i == 5; // weird, but nothing stops you
                       // from doing so
    }

};

int main()
{
  std::vector<Example> v(10);
  // ...
  auto it = std::remove(v.begin(), v.end(), Example());
  // ...
}

यदि std::removeउपयोग किया जाता है operator!=, तो परिणाम काफी अलग होगा।


1
विचार करने के लिए एक और बात यह है कि यह संभव हो सकता है दोनों के लिए a==bऔर a!=bझूठे वापस करने के लिए। हालांकि यह हमेशा स्पष्ट नहीं हो सकता है कि इस तरह की स्थिति को और अधिक "समान" या "नहीं-बराबर" के रूप में माना जाएगा, एक फ़ंक्शन जो "==" ऑपरेटर के संदर्भ में समानता को पूरी तरह से परिभाषित करता है, उन्हें "नहीं-बराबर" के रूप में मानना ​​चाहिए ", इस बात की परवाह किए बिना कि कौन सा व्यवहार अधिक समझ में आएगा [अगर मेरे शराबी थे, तो सभी प्रकार के बूलियन-उपज बनाने की उम्मीद की जाएगी" == "और"! = "" ऑपरेटर लगातार व्यवहार करते हैं, लेकिन तथ्य यह है कि IEEE-754 गेट्स ने समानता को तोड़ दिया! ऑपरेटरों को ऐसी उम्मीद करना मुश्किल होगा]।
सुपरकैट

18
"सख्त भाषा के दृष्टिकोण से, जो कोड आप देख रहे हैं वह मौजूद नहीं है।" - जब देखने का एक बिंदु कहता है कि कुछ मौजूद नहीं है, लेकिन आप वास्तव में उस चीज को देख रहे हैं, तो देखने की बात गलत है। वास्तव में मानक यह नहीं कहता है कि कोड मौजूद नहीं है, यह केवल यह नहीं कहता है कि यह मौजूद नहीं है :-)
स्टीव जेसप

@SteveJessop: आप "सख्त भाषा के दृष्टिकोण से" को "कड़ाई से भाषा पर" जैसी किसी चीज़ से बदल सकते हैं। मुद्दा यह है कि ओपी द्वारा पोस्ट किया गया कोड भाषा मानक की चिंता नहीं है।
क्रिश्चियन हैकल

2
@ सुपरकैट: IEEE-754 लगातार बनाता है ==और !=व्यवहार करता है , हालांकि मैंने हमेशा सोचा है कि सभी छह संबंधों का मूल्यांकन करना चाहिए कि falseकम से कम एक ऑपरेंड कब है NaN
बेन वोइग्ट सेप

@BenVoigt: आह, यह सही है। यह दो ऑपरेटरों को एक ही टूटे हुए फैशन में व्यवहार करता है जैसे कि वे एक-दूसरे के साथ संगत होते हैं, लेकिन फिर भी तुल्यता से जुड़े अन्य सभी सामान्य स्वयंसिद्धों का उल्लंघन करने का प्रबंधन करते हैं (जैसे वे न तो == ए और न ही गारंटी देते हैं कि ऑपरेशन किए गए। समान मूल्यों पर समान परिणाम प्राप्त करेंगे)।
18

15

कुछ अच्छे जवाब यहाँ। मैं सिर्फ एक छोटा सा नोट जोड़ना चाहता था।

सभी अच्छे पुस्तकालयों की तरह, मानक पुस्तकालय को दो महत्वपूर्ण सिद्धांतों को ध्यान में रखते हुए तैयार किया गया है:

  1. अपने पुस्तकालय के उन उपयोगकर्ताओं पर कम से कम जिम्मेदारी डालें जिन्हें आप दूर कर सकते हैं। इसका एक हिस्सा उन्हें अपने इंटरफ़ेस का उपयोग करते समय कम से कम काम करने के लिए करना है। (जैसा कि आप के साथ दूर कर सकते हैं के रूप में कुछ ऑपरेटरों को परिभाषित करना)। इसका दूसरा हिस्सा उन्हें आश्चर्यचकित न करने या त्रुटि कोड की जांच करने की आवश्यकता के साथ करना है (ताकि <stdexcept>जब चीजें गलत हों तो अपवादों को संगत रखें और अपवादों को फेंक दें )।

  2. सभी तार्किक अतिरेक को हटा दें । सभी तुलनाओं को केवल से घटाया जा सकता है operator<, इसलिए उपयोगकर्ता दूसरों को परिभाषित करने की मांग क्यों करते हैं? उदाहरण के लिए:

    (ए> बी) के बराबर है (बी <ए)

    (a> = b) के बराबर है! (a <b)

    (a == b) इसके बराबर है! ((a <b) || (b <a))

    और इसी तरह।

    इस नोट पर, कोई यह पूछ सकता है कि unordered_mapइसके operator==बजाय (कम से कम डिफ़ॉल्ट रूप से) की आवश्यकता क्यों है operator<। इसका उत्तर यह है कि एक हैश टेबल में केवल एक ही तुलना की आवश्यकता होती है जो समानता के लिए एक है। इस प्रकार यह अधिक तार्किक रूप से सुसंगत है (अर्थात पुस्तकालय उपयोगकर्ता के लिए अधिक समझ में आता है) उन्हें एक समानता ऑपरेटर को परिभाषित करने की आवश्यकता होती है। आवश्यकता operator<होती है भ्रामक क्योंकि यह तुरंत स्पष्ट नहीं है कि आपको इसकी आवश्यकता क्यों होगी।


10
आपके दूसरे बिंदु के बारे में: ऐसे प्रकार हैं जिनकी तार्किक रूप से समानता के लिए तुलना की जा सकती है, भले ही कोई तार्किक आदेश मौजूद न हो, या जिसके लिए ऑर्डर स्थापित करना बहुत ही कृत्रिम होगा। उदाहरण के लिए, लाल लाल है और लाल हरा नहीं है, लेकिन लाल स्वाभाविक रूप से हरे रंग से कम है?
क्रिश्चियन हैकल

1
पूरी तरह से सहमत हूँ। कोई इन वस्तुओं को एक ऑर्डर किए गए कंटेनर में संग्रहीत नहीं करेगा क्योंकि कोई तार्किक आदेश नहीं है। वे अधिक उपयुक्त रूप से एक अनियंत्रित कंटेनर में संग्रहीत किए जा सकते हैं जिसके लिए operator==(और hash) की आवश्यकता होती है ।
रिचर्ड होजेस

3. अधिभार कम से कम संभव के रूप में मानक ऑपरेटरों। यह एक और कारण है कि उन्होंने लागू किया !(a==b)। क्योंकि संचालकों के अतिक्रमित ओवरलोडिंग के कारण आसानी से C ++ प्रोग्राम पूरी तरह से गड़बड़ा सकता है (साथ ही, प्रोग्रामर को पागल कर सकता है क्योंकि उसके कोड को डीबग करना एक मिशन असंभव हो सकता है, क्योंकि किसी विशेष बग का अपराधी एक ओडिसी जैसा दिख रहा है)।
सिंटेक्सैरोर

!((a < b) || (b < a))एक कम बूल ऑपरेटर का उपयोग करता है, इसलिए यह संभवत: तेज है
फिलिप हाग्लंड

1
वास्तव में वे नहीं करते। असेंबली भाषा में सभी तुलनाओं को झंडे के रजिस्टर में कैरी और ज़ीरो बिट्स के परीक्षण के बाद घटाव के रूप में लागू किया जाता है। बाकी सब कुछ सिर्फ सिंथेटिक चीनी है।
रिचर्ड

8

EqualityComparableअवधारणा केवल आवश्यकता है कि operator==परिभाषित किया जा।

नतीजतन, कोई भी फ़ंक्शन जो कि संतोषजनक प्रकारों के साथ काम करता है , उस प्रकार की वस्तुओं के अस्तित्व पर भरोसा EqualityComparable नहीं कर सकता हैoperator!= । (जब तक कि अतिरिक्त आवश्यकताएं न हों, तब तक इसका अस्तित्व है operator!=)।


1

सबसे आशाजनक दृष्टिकोण यह निर्धारित करने की एक विधि खोजना है कि क्या ऑपरेटर == को किसी विशेष प्रकार के लिए बुलाया जा सकता है, और फिर उपलब्ध होने पर ही इसका समर्थन कर सकता है; अन्य स्थितियों में, एक अपवाद को फेंक दिया जाएगा। हालांकि, आज तक यह पता लगाने का कोई ज्ञात तरीका नहीं है कि क्या एक मनमाना ऑपरेटर अभिव्यक्ति f == जी उपयुक्त रूप से परिभाषित है। ज्ञात सबसे अच्छा समाधान में निम्नलिखित अवांछनीय गुण हैं:

  • जिन संचालकों के लिए संकलन-समय पर विफल रहता है, जहां ऑपरेटर == सुलभ नहीं है (उदाहरण के लिए, क्योंकि यह निजी है)।
  • संचालक समय पर विफल रहता है यदि कॉलिंग ऑपरेटर == अस्पष्ट है।
  • ऑपरेटर == घोषणा सही है, तो भी सही प्रतीत होता है, भले ही ऑपरेटर == संकलित न हो।

बूस्ट एफएक्यू से: स्रोत

यह जानकर कि ==कार्यान्वयन की आवश्यकता एक बोझ है , आप कभी भी !=कार्यान्वयन की आवश्यकता के द्वारा अतिरिक्त बोझ नहीं बनाना चाहते हैं ।

मेरे लिए व्यक्तिगत रूप से यह SOLID (ऑब्जेक्ट-ओरिएंटेड डिज़ाइन) L पार्ट - Liskov प्रतिस्थापन सिद्धांत के बारे में है: "प्रोग्राम में ऑब्जेक्ट्स को उस प्रोग्राम की शुद्धता में बदलाव किए बिना उनके उपप्रकारों के उदाहरणों के साथ बदली जा सकती है।" इस मामले में यह ऑपरेटर है ! = कि मैं बूलियन लॉजिक में == और बूलियन प्रतिलोम के साथ प्रतिस्थापित कर सकता हूं ।

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