C ++ कंपाइलर ऑपरेटर == और ऑपरेटर = को परिभाषित क्यों नहीं करते?


302

मैं कंपाइलर को आपके लिए ज्यादा से ज्यादा काम करने देने का बहुत बड़ा प्रशंसक हूं। एक साधारण वर्ग लिखते समय कंपाइलर आपको 'मुफ्त' में दे सकता है:

  • एक डिफ़ॉल्ट (खाली) कंस्ट्रक्टर
  • एक कॉपी कंस्ट्रक्टर
  • एक विध्वंसक
  • एक असाइनमेंट ऑपरेटर ( operator=)

लेकिन यह आपको कोई तुलना करने वाला ऑपरेटर नहीं दे सकता है - जैसे operator==या operator!=। उदाहरण के लिए:

class foo
{
public:
    std::string str_;
    int n_;
};

foo f1;        // Works
foo f2(f1);    // Works
foo f3;
f3 = f2;       // Works

if (f3 == f2)  // Fails
{ }

if (f3 != f2)  // Fails
{ }

क्या इसका कोई अच्छा कारण है? सदस्य-दर-सदस्य तुलना करना एक समस्या क्यों होगी? जाहिर है अगर वर्ग स्मृति आवंटित करता है तो आप सावधान रहना चाहते हैं, लेकिन एक साधारण वर्ग के लिए निश्चित रूप से कंपाइलर आपके लिए ऐसा कर सकता है?


4
बेशक, यह भी विनाशकारी मुफ्त में प्रदान किया जाता है।
जोहान जेरेल

23
अपनी हालिया वार्ता में, एलेक्स स्टेपानोव ने बताया कि यह डिफ़ॉल्ट स्वचालित नहीं होने की गलती थी ==, उसी तरह से =कुछ शर्तों के तहत एक डिफ़ॉल्ट स्वचालित असाइनमेंट ( ) है। (संकेत के बारे में तर्क असंगत क्योंकि तर्क के लिए दोनों पर लागू होता है है =और ==, और न सिर्फ दूसरे के लिए)।
alfC

2
@becko यह A9: youtube.com/watch?v=k-meLQaYP5Y श्रृंखला में एक है , मुझे याद नहीं है कि किन-किन वार्ताओं में। एक प्रस्ताव यह भी है कि यह C ++ 17 ओपन-std.org/JTC1/SC22/WG21/docs/papers/2016/p0221r0.html
alfC

1
@becko, यह या तो श्रृंखला में पहले में से एक है, "घटकों के साथ कुशल प्रोग्रामिंग" या ए 9 में दोनों में "प्रोग्रामिंग वार्तालाप" दोनों।
alfC

1
@becko वास्तव में एलेक्स के दृष्टिकोण को इंगित करने के लिए नीचे एक उत्तर है stackoverflow.com/a/23329089/225186
alfC

जवाबों:


71

कंपाइलर को पता नहीं चलेगा कि आपको पॉइंटर तुलना या गहरी (आंतरिक) तुलना चाहिए थी या नहीं।

यह सिर्फ इसे लागू नहीं करने के लिए सुरक्षित है और प्रोग्रामर को खुद ऐसा करने दें। तब वे अपनी पसंद की सभी धारणाएँ बना सकते हैं।


292
यह समस्या इसे कॉपी कॉटर उत्पन्न करने से नहीं रोकती है, जहां यह काफी हानिकारक है।
9

78
कॉपी कंस्ट्रक्टर (और operator=) आम तौर पर तुलना ऑपरेटरों के रूप में एक ही संदर्भ में काम करते हैं - अर्थात, एक उम्मीद है कि आपके प्रदर्शन के बाद a = b, a == bयह सच है। यह निश्चित रूप से संकलक के लिए operator==समान एग्रीगेट वैल्यू शब्दार्थ का उपयोग करके डिफ़ॉल्ट प्रदान करने के लिए समझ में आता है operator=। मुझे संदेह है कि वास्तव में पेरेसबल यहां सही है operator=(और प्रतिलिपि ctor) पूरी तरह से C संगतता के लिए प्रदान की जाती है, और वे किसी भी स्थिति को बदतर नहीं बनाना चाहते थे।
पावेल मिनावे

46
-1। बेशक आप एक गहरी तुलना चाहते हैं, अगर प्रोग्रामर एक सूचक तुलना चाहता था, तो वह लिखेगा (& f1 == & f2)
विक्टर सेहर

62
विक्टर, मेरा सुझाव है कि आप अपनी प्रतिक्रिया पर फिर से विचार करें। यदि क्लास फू में एक बार * होता है, तो कंपाइलर को कैसे पता चलेगा कि फू @ ऑपरेटर == बार * के पते की तुलना करना चाहता है या बार की सामग्री की?
मार्क इंग्राम

46
@ मर्क: यदि इसमें एक पॉइंटर है, तो पॉइंटर मूल्यों की तुलना करना उचित है - यदि इसमें मान है, तो मूल्यों की तुलना करना उचित है। असाधारण परिस्थितियों में, प्रोग्रामर ओवरराइड कर सकता है। यह भाषा की तरह ही है, जो कि ints और पॉइंटर-टू-इनट्स के बीच तुलना करता है।
Eamon Nerbonne

317

यह तर्क कि यदि कंपाइलर एक डिफ़ॉल्ट कॉपी कंस्ट्रक्टर प्रदान कर सकता है, तो उसे एक समान डिफ़ॉल्ट प्रदान करने में सक्षम होना चाहिए operator==()जो एक निश्चित मात्रा में समझ में आता है। मुझे लगता है कि इस ऑपरेटर के लिए एक कंपाइलर-जनरेटेड डिफॉल्ट प्रदान नहीं करने के निर्णय का कारण स्ट्रॉस्ट्रुप द्वारा "द डिजाइन एंड इवोल्यूशन ऑफ सी ++" (धारा 11.4.1 - नियंत्रण का नियंत्रण) में डिफ़ॉल्ट कॉपी कंस्ट्रक्टर के बारे में क्या कहा जा सकता है। :

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

इसलिए "C ++ में डिफ़ॉल्ट क्यों नहीं है operator==()?" के बजाय , सवाल यह होना चाहिए कि "C ++ में डिफ़ॉल्ट असाइनमेंट और कॉपी कंस्ट्रक्टर क्यों है?", इस उत्तर के साथ उन वस्तुओं को अनिच्छा से Stroustrup द्वारा बैकवर्ड संगतता के लिए C से शामिल किया गया था। (शायद C ++ के मौसा के अधिकांश का कारण, लेकिन संभवतः C ++ की लोकप्रियता का प्राथमिक कारण भी है)।

अपने स्वयं के प्रयोजनों के लिए, मेरी आईडीई में नई कक्षाओं के लिए मेरे द्वारा उपयोग किए जाने वाले स्निपेट में एक निजी असाइनमेंट ऑपरेटर और कॉपी कंस्ट्रक्टर के लिए घोषणाएं शामिल हैं ताकि जब मैं एक नया वर्ग तैयार करूं तो मुझे कोई डिफ़ॉल्ट असाइनमेंट और कॉपी ऑपरेशन न मिले - मुझे स्पष्ट रूप से घोषणा को हटाना होगा private:यदि मैं चाहता हूं कि संकलक उन संचालनों के संचालन से मेरे लिए उन्हें उत्पन्न करने में सक्षम हो।


29
अच्छा उत्तर। मैं केवल यह Foo(const Foo&) = delete; // no copy constructorFoo& Foo=(const Foo&) = delete; // no assignment operator
बताना

9
"हालांकि, C ++ को अपना डिफ़ॉल्ट असाइनमेंट विरासत में मिला है और C से कंस्ट्रक्टर्स को कॉपी किया है" इसका मतलब यह नहीं है कि आपको इस तरह से सभी C ++ टाइप करने हैं। उन्हें इसे केवल पुराने पुराने PODs तक सीमित रखना चाहिए, बस वे प्रकार जो पहले से C में हैं, अब और नहीं।
thesaint

3
मैं निश्चित रूप से समझ सकता हूं कि C ++ को इन व्यवहारों के लिए विरासत में क्यों मिला struct, लेकिन मैं चाहता हूं कि यह classअलग तरीके से व्यवहार करे (और पूरी तरह से)। इस प्रक्रिया में, यह डिफ़ॉल्ट पहुँच के साथ structऔर classउसके बीच एक अधिक सार्थक अंतर देता है ।
jamesdlin

@jamesdlin यदि आप एक नियम चाहते हैं, तो अंतर्निहित घोषणा और अक्षमता की परिभाषा और असाइनमेंट को निष्क्रिय करना अगर एक डॉटर घोषित किया जाता है तो सबसे अधिक समझ में आएगा।
डेडुप्लिकेटर

1
मैं अभी भी प्रोग्रामर को कंपाइलर बनाने के लिए स्पष्ट रूप से आदेश देने में कोई बुराई नहीं देखता हूं operator==। इस बिंदु पर यह कुछ बॉयलर-प्लेट कोड के लिए सिंटैक्स चीनी है। यदि आप डरते हैं कि इस तरह से प्रोग्रामर क्लास फ़ील्ड्स के बीच कुछ पॉइंटर को नजरअंदाज कर सकता है, तो आप एक शर्त जोड़ सकते हैं कि यह केवल आदिम प्रकार और ऑब्जेक्ट्स पर काम कर सकता है जिनके पास स्वयं समानता ऑपरेटर हैं। हालांकि इसे पूरी तरह से खारिज करने का कोई कारण नहीं है।
NO_NAME

93

C ++ 20 में भी, कंपाइलर अभी भी operator==आपके लिए निहित नहीं होगा

struct foo
{
    std::string str;
    int n;
};

assert(foo{"Anton", 1} == foo{"Anton", 1}); // ill-formed

लेकिन आप C ++ 20 के बाद से स्पष्ट रूप == से डिफ़ॉल्ट करने की क्षमता हासिल करेंगे :

struct foo
{
    std::string str;
    int n;

    // either member form
    bool operator==(foo const&) const = default;
    // ... or friend form
    friend bool operator==(foo const&, foo const&) = default;
};

दोषी ==सदस्य वार करता है ==(एक ही तरीका है कि डिफ़ॉल्ट प्रतिलिपि निर्माता सदस्य के लिहाज से प्रति निर्माण करता है)। नए नियम भी ==और के बीच अपेक्षित संबंध प्रदान करते हैं !=। उदाहरण के लिए, उपरोक्त घोषणा के साथ, मैं दोनों लिख सकता हूं:

assert(foo{"Anton", 1} == foo{"Anton", 1}); // ok!
assert(foo{"Anton", 1} != foo{"Anton", 2}); // ok!

यह विशिष्ट सुविधा (चूक operator==और के बीच समरूपता ==और !=) से आता है एक प्रस्ताव यह है कि व्यापक भाषा सुविधा का हिस्सा था operator<=>


क्या आप जानते हैं कि इस पर कोई और हालिया अपडेट है? क्या यह c ++ 17 में उपलब्ध होने वाला है?
dcmm88

3
@ dcmm88 Uh दुर्भाग्य से यह C ++ 17 में उपलब्ध नहीं होगा। मैंने जवाब अपडेट कर दिया है।
एंटोन सेविन

2
एक संशोधित प्रस्ताव जो समान चीज़ की अनुमति देता है (संक्षिप्त रूप को छोड़कर) C ++ 20 में होने जा रहा है, हालांकि :)
Rakete1111

तो मूल रूप से आपको उस = defaultचीज़ के लिए निर्दिष्ट करना होगा , जो डिफ़ॉल्ट रूप से नहीं बनाई गई है, है ना? यह मेरे लिए ऑक्सीमोरोन जैसा लगता है ("स्पष्ट डिफ़ॉल्ट")।
आर्टिन

@ आर्टिन यह समझ में आता है कि भाषा में नई सुविधाओं को जोड़ने से मौजूदा कार्यान्वयन को नहीं तोड़ना चाहिए। नए पुस्तकालय मानकों या नई चीजों को संकलक जोड़ना एक बात है। नए सदस्य फ़ंक्शंस जोड़ना जहां वे पहले से मौजूद नहीं थे, पूरी अलग कहानी है। गलतियों से अपनी परियोजना को सुरक्षित करने के लिए इसे और अधिक प्रयास की आवश्यकता होगी। मैं व्यक्तिगत रूप से संकलक ध्वज को स्पष्ट और अंतर्निहित डिफ़ॉल्ट के बीच स्विच करना पसंद करूंगा। आप पुराने C ++ मानक से प्रोजेक्ट बनाते हैं, कंपाइलर फ्लैग द्वारा स्पष्ट डिफ़ॉल्ट का उपयोग करते हैं। आप पहले से ही कंपाइलर को अपडेट करते हैं, इसलिए आपको इसे ठीक से कॉन्फ़िगर करना चाहिए। नई परियोजनाओं के लिए यह निहित है।
मैकीज ज़ुल्काई

44

IMHO, कोई "अच्छा" कारण नहीं है। बहुत से लोग ऐसे हैं जो इस डिजाइन के फैसले से सहमत हैं क्योंकि उन्होंने मूल्य-आधारित शब्दार्थ की शक्ति में महारत हासिल करना नहीं सीखा है। लोगों को बहुत सारे कस्टम कॉपी कंस्ट्रक्टर, तुलना ऑपरेटरों और विध्वंसक लिखने की जरूरत है क्योंकि वे अपने कार्यान्वयन में कच्चे पॉइंटर्स का उपयोग करते हैं।

उपयुक्त स्मार्ट पॉइंटर्स (जैसे std :: shared_ptr) का उपयोग करते समय, डिफ़ॉल्ट कॉपी कंस्ट्रक्टर आमतौर पर ठीक है और काल्पनिक डिफ़ॉल्ट तुलना ऑपरेटर का स्पष्ट कार्यान्वयन उतना ही ठीक होगा।


39

इसका उत्तर है C ++ ने == नहीं किया, क्योंकि C ने नहीं किया, और इसीलिए C पहले स्थान पर केवल डिफ़ॉल्ट = लेकिन नहीं == प्रदान करता है। C इसे सरल रखना चाहता था: C कार्यान्वित = memcpy द्वारा; हालाँकि, == को पैडिंग की वजह से मेमकैंप द्वारा लागू नहीं किया जा सकता है। क्योंकि पैडिंग को इनिशियलाइज़ नहीं किया गया है, मेम्कैंप का कहना है कि वे अलग-अलग हैं, भले ही वे समान हों। खाली वर्ग के लिए भी यही समस्या है: मेमचैंप का कहना है कि वे अलग हैं क्योंकि खाली कक्षाओं का आकार शून्य नहीं है। यह ऊपर से देखा जा सकता है कि == सी में लागू करने की तुलना में अधिक जटिल है = सी । इस बारे में कुछ कोड उदाहरण । अगर मैं गलत हूं तो आपके सुधार की सराहना की जाती है।


6
C ++ मेमेकपी का उपयोग नहीं करता है operator=- जो केवल POD प्रकारों के लिए काम करेगा, लेकिन C ++ operator=गैर POD प्रकारों के लिए भी एक डिफ़ॉल्ट प्रदान करता है।
फ्लेक्सो

2
हाँ, C ++ को अधिक परिष्कृत तरीके से लागू किया गया। ऐसा लगता है कि सी सिर्फ लागू किया गया है = एक साधारण ज्ञापन के साथ।
रियो विंग

इस उत्तर की सामग्री को माइकल के साथ रखा जाना चाहिए। उसका सवाल सही है तो यह उसका जवाब देता है।
Sgene9

27

इस वीडियो में एसटीएल के निर्माता एलेक्स स्टेपानोव ने लगभग 13:00 बजे इस प्रश्न को संबोधित किया। संक्षेप में, C ++ के विकास को देखने के बाद उनका तर्क है कि:

  • यह दुर्भाग्यपूर्ण है कि == और! = स्पष्ट रूप से घोषित नहीं हैं (और बज़्ने उससे सहमत हैं)। एक सही भाषा में आपके लिए वे चीजें तैयार होनी चाहिए (वह आगे सुझाव देता है कि आपको एक परिभाषित करने में सक्षम नहीं होना चाहिए ! = जो शब्दार्थ == को तोड़ता है )
  • इसका कारण यह है कि सी में इसकी जड़ें (C ++ की कई समस्याओं के रूप में) हैं। असाइनमेंट ऑपरेटर को बिट बिट असाइनमेंट के साथ स्पष्ट रूप से परिभाषित किया गया है, लेकिन यह == के लिए काम नहीं करेगा । इस आलेख में ब्रेज़न स्ट्रॉस्ट्रुप से अधिक विस्तृत विवरण पाया जा सकता है ।
  • अनुवर्ती प्रश्न में, तब सदस्य तुलना द्वारा सदस्य क्यों नहीं था, इसका उपयोग वह एक अद्भुत बात कहता है : सी एक देसी भाषा की तरह था और रिची के लिए इन सामानों को लागू करने वाले व्यक्ति ने उसे बताया कि उसे इसे लागू करने के लिए कठिन लगता है!

फिर वह कहता है कि (दूर) भविष्य में == और ! = अंतर्निहित रूप से उत्पन्न होगा।


2
ऐसा लगता है कि यह दूर भविष्य 2017 नहीं जा रहा है और न ही 18, न ही 19, अच्छी तरह से आप मेरे बहाव को
पकड़ते हैं

18

C ++ 20 डिफ़ॉल्ट तुलना ऑपरेटर को आसानी से लागू करने का एक तरीका प्रदान करता है।

Cppreference.com से उदाहरण :

class Point {
    int x;
    int y;
public:
    auto operator<=>(const Point&) const = default;
    // ... non-comparison functions ...
};

// compiler implicitly declares operator== and all four relational operators work
Point pt1, pt2;
if (pt1 == pt2) { /*...*/ } // ok, calls implicit Point::operator==
std::set<Point> s; // ok
s.insert(pt1); // ok
if (pt1 <= pt2) { /*...*/ } // ok, makes only a single call to Point::operator<=>

4
मुझे आश्चर्य है कि उन्होंने Pointएक ऑर्डरिंग ऑपरेशन के लिए एक उदाहरण के रूप में उपयोग किया है , क्योंकि दो बिंदुओं के साथ xऔर yनिर्देशांक करने के लिए कोई उचित डिफ़ॉल्ट तरीका नहीं है ...
पाइप

4
@ अगर आप ध्यान नहीं देते हैं कि तत्व किस क्रम में हैं, तो डिफ़ॉल्ट ऑपरेटर का उपयोग करना समझ में आता है। उदाहरण के लिए, आप std::setयह सुनिश्चित करने के लिए उपयोग कर सकते हैं कि सभी बिंदु अद्वितीय हैं, और केवल std::setउपयोग करता है operator<
vll

वापसी प्रकार के बारे में auto: इस मामले के लिए क्या हम हमेशा मान सकते हैं कि यह कहां std::strong_orderingसे होगा #include <compare>?
केविनरपे

1
@kevinarpe वापसी प्रकार है std::common_comparison_category_t, जो इस वर्ग के लिए डिफ़ॉल्ट क्रम ( std::strong_ordering) बन जाता है ।
vll

15

डिफ़ॉल्ट को परिभाषित करना संभव नहीं है ==, लेकिन आप डिफ़ॉल्ट को परिभाषित कर सकते हैं जिसके !=माध्यम ==से आपको आमतौर पर खुद को परिभाषित करना चाहिए। इसके लिए आपको निम्नलिखित बातें करनी चाहिए:

#include <utility>
using namespace std::rel_ops;
...

class FooClass
{
public:
  bool operator== (const FooClass& other) const {
  // ...
  }
};

आप विवरण के लिए http://www.cplusplus.com/reference/std/utility/rel_ops/ देख सकते हैं ।

इसके अलावा यदि आप परिभाषित करते हैं operator< , तो <=,>,> = के लिए ऑपरेटरों का उपयोग करते समय इसे से घटाया जा सकता है std::rel_ops

लेकिन जब आप उपयोग करते हैं तो आपको सावधान रहना चाहिए std::rel_opsक्योंकि तुलनात्मक ऑपरेटरों को उन प्रकारों के लिए घटाया जा सकता है जिनके लिए आप अपेक्षित नहीं हैं।

बुनियादी ऑपरेटर से संबंधित ऑपरेटर को कम करने का अधिक पसंदीदा तरीका बढ़ावा देने का उपयोग करना है :: ऑपरेटरों

बूस्ट में उपयोग किया जाने वाला दृष्टिकोण बेहतर है क्योंकि यह केवल आपके इच्छित वर्ग के लिए ऑपरेटर के उपयोग को परिभाषित करता है, न कि सभी वर्गों के लिए।

आप "+" से "+" भी उत्पन्न कर सकते हैं, - "- =", आदि से ... ( यहां पूरी सूची देखें )


ऑपरेटर !=लिखने के बाद मुझे डिफ़ॉल्ट नहीं मिला ==। या मैंने किया लेकिन इसमें constनेस की कमी थी । खुद भी लिखना था और सब ठीक था।
जॉन

आप आवश्यक परिणाम प्राप्त करने के लिए कॉन्स्ट-नेस के साथ खेल सकते हैं। कोड के बिना यह कहना मुश्किल है कि इसके साथ क्या गलत है।
18

2
वहाँ एक कारण rel_opsC ++ 20 में पदावनत किया गया था: क्योंकि यह काम नहीं करता है , कम से कम हर जगह नहीं, और निश्चित रूप से लगातार नहीं। sort_decreasing()संकलन करने के लिए कोई विश्वसनीय तरीका नहीं है । दूसरी ओर, Boost.Operators काम करता है और हमेशा काम करता है।
बैरी

10

C ++ 0x में डिफ़ॉल्ट कार्यों के लिए एक प्रस्ताव था, इसलिए आप कह सकते हैं कि default operator==; हमने सीखा है कि यह इन चीजों को स्पष्ट करने में मदद करता है।


3
मैंने सोचा था कि केवल "विशेष सदस्य फ़ंक्शंस" (डिफ़ॉल्ट कंस्ट्रक्टर, कॉपी कंस्ट्रक्टर, असाइनमेंट ऑपरेटर और डिस्ट्रक्टर) को स्पष्ट रूप से डिफ़ॉल्ट किया जा सकता है। क्या उन्होंने इसे कुछ अन्य ऑपरेटरों के लिए बढ़ाया है?
माइकल बूर

4
मूव कंस्ट्रक्टर को भी डिफ़ॉल्ट किया जा सकता है, लेकिन मुझे नहीं लगता कि यह लागू होता है operator==। जो एक दया है।
पावेल मिनावे

5

वैचारिक रूप से समानता को परिभाषित करना आसान नहीं है। यहां तक ​​कि POD डेटा के लिए, कोई यह तर्क दे सकता है कि भले ही फ़ील्ड समान हों, लेकिन यह एक अलग ऑब्जेक्ट है (एक अलग पते पर) यह आवश्यक नहीं है कि समान है। यह वास्तव में ऑपरेटर के उपयोग पर निर्भर करता है। दुर्भाग्य से आपका कंपाइलर मानसिक नहीं है और यह अनुमान नहीं लगा सकता है।

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


10
पीओडी संरचनाओं के लिए कोई अस्पष्टता नहीं है - उन्हें ठीक उसी तरह से व्यवहार करना चाहिए जैसे कोई अन्य पीओडी प्रकार करता है, जो मूल्य समानता है (बल्कि संदर्भ समानता)। एक intदूसरे से प्रतिलिपि ctor के माध्यम से बनाई गई एक के बराबर है जिसमें से इसे बनाया गया था; केवल structदो intक्षेत्रों के लिए करने के लिए एकमात्र तार्किक बात यह है कि ठीक उसी तरह से काम करना है।
पावेल मिनाएव

1
@ मिगुका: मैं एक सार्वभौमिक तुल्यता संबंध के लिए काफी उपयोगिता देख सकता हूं जो किसी भी प्रकार की अनुमति देता है जो एक शब्दकोश या समान संग्रह में एक कुंजी के रूप में उपयोग किए जाने वाले मूल्य के रूप में व्यवहार करता है। हालांकि इस तरह के संग्रह एक गारंटीकृत-प्रतिवर्तनीय तुल्यता संबंध के बिना उपयोगी व्यवहार नहीं कर सकते हैं। IMHO, सबसे अच्छा समाधान एक नए ऑपरेटर को परिभाषित करना होगा जो सभी अंतर्निहित प्रकार समझदारी से लागू कर सकता है, और कुछ नए सूचक प्रकारों को परिभाषित कर सकता है जो मौजूदा लोगों की तरह थे सिवाय इसके कि कुछ समानता को संदर्भ समकक्षता के रूप में परिभाषित करेंगे जबकि अन्य लक्ष्य के लिए चेन करेंगे समकक्ष ऑपरेटर।
सुपरकैट

1
सादृश्य द्वारा, आप +संचालक के लिए लगभग एक ही तर्क दे सकते हैं कि यह फ्लोट के लिए गैर-सहयोगी है; जिस तरह से (x + y) + z! = x + (y + z), एफपी गोलाई के तरीके के कारण होता है। (यकीनन, यह ==सामान्य संख्यात्मक मानों के लिए सही होने की तुलना में कहीं अधिक खराब समस्या है ।) आप एक नया अतिरिक्त ऑपरेटर जोड़ने का सुझाव दे सकते हैं जो सभी संख्यात्मक प्रकारों (यहां तक ​​कि इंट) के लिए काम करता है और लगभग वैसा ही है, +लेकिन यह सहयोगी है ( किसी न किसी तरह)। लेकिन तब आप वास्तव में कई लोगों की मदद के बिना भाषा में ब्लोट और भ्रम जोड़ रहे होंगे।
मगुआका

1
@ मिगुका: जिन चीजों के किनारे मामले को छोड़कर काफी समान होते हैं, वे अक्सर बेहद उपयोगी होते हैं, और ऐसी चीजों से बचने के लिए गुमराह करने वाले प्रयासों का परिणाम बहुत ही अनावश्यक होता है। यदि क्लाइंट कोड को कभी-कभी किनारे के मामलों को एक तरह से संभालने की आवश्यकता होगी, और कभी-कभी उन्हें दूसरे को संभालने की आवश्यकता होगी, तो हैंडलिंग की प्रत्येक शैली के लिए एक विधि होने से क्लाइंट में बहुत सारे किनारे-केस-हैंडलिंग कोड समाप्त हो जाएंगे। अपने सादृश्य के रूप में, सभी मामलों में सकर्मक परिणाम प्राप्त करने के लिए निश्चित आकार के फ्लोटिंग-पॉइंट मूल्यों पर ऑपरेशन को परिभाषित करने का कोई तरीका नहीं है (हालांकि कुछ 1980 के दशक की भाषाओं में बेहतर शब्दार्थ था ...
सुपरकैट

1
... उस संबंध में आज की तुलना में) और इस तरह यह तथ्य कि वे असंभव नहीं करते हैं, आश्चर्य नहीं होना चाहिए। हालांकि, कोई मौलिक बाधा नहीं है, एक तुल्यता संबंध को लागू करने के लिए जो सार्वभौमिक रूप से किसी भी प्रकार के मूल्य पर लागू होगा जिसे कॉपी किया जा सकता है।
सुपरकैट

1

क्या इसका कोई अच्छा कारण है? सदस्य-दर-सदस्य तुलना करना एक समस्या क्यों होगी?

यह कार्यात्मक रूप से एक समस्या नहीं हो सकती है, लेकिन प्रदर्शन के मामले में, डिफ़ॉल्ट सदस्य-दर-सदस्य तुलना डिफ़ॉल्ट सदस्य-द्वारा-सदस्य असाइनमेंट / प्रतिलिपि की तुलना में अधिक उप-इष्टतम होने के लिए उत्तरदायी है। असाइनमेंट के आदेश के विपरीत, तुलना का क्रम प्रदर्शन को प्रभावित करता है क्योंकि पहले असमान सदस्य का तात्पर्य है बाकी को छोड़ दिया जा सकता है। इसलिए यदि कुछ सदस्य ऐसे हैं जो आमतौर पर समान होते हैं तो आप उनकी तुलना पिछले से करना चाहते हैं, और संकलक को यह नहीं पता है कि कौन से सदस्य समान होने की अधिक संभावना है।

इस उदाहरण पर विचार करें, जहां verboseDescription एक लंबी स्ट्रिंग संभव मौसम विवरणों के अपेक्षाकृत छोटे सेट से चुनी गई है।

class LocalWeatherRecord {
    std::string verboseDescription;
    std::tm date;
    bool operator==(const LocalWeatherRecord& other){
        return date==other.date
            && verboseDescription==other.verboseDescription;
    // The above makes a lot more sense than
     // return verboseDescription==other.verboseDescription
     //     && date==other.date;
    // because some verboseDescriptions are liable to be same/similar
    }
}

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


लेकिन कोई भी आपको एक अनुकूलन उपयोगकर्ता-परिभाषित तुलना लिखने से नहीं रखता है यदि आप एक प्रदर्शन समस्या पाते हैं। मेरे अनुभव में हालांकि मामलों का एक छोटा अल्पसंख्यक होगा।
पीटर -

1

बस इतना है कि इस सवाल का जवाब पूरा हो गया है जैसे ही समय गुजरता है: C ++ 20 के बाद से यह स्वचालित रूप से कमांड के साथ उत्पन्न हो सकता है auto operator<=>(const foo&) const = default;

यह सभी ऑपरेटरों को उत्पन्न करेगा: ==,! =, <, <=>, और> =, https://en.cppreference.com/w/cpp/language/default_comparison देखें विवरण के लिए देखें।

ऑपरेटर के लुक के कारण <=>इसे स्पेसशिप ऑपरेटर कहा जाता है। यह भी देखें कि हमें C ++ में स्पेसशिप <=> ऑपरेटर की आवश्यकता क्यों है?

संपादित करें: C ++ 11 में भी इसके लिए एक सुंदर स्वच्छ विकल्प उपलब्ध है जो std::tieकि https://en.cppreference.com/w/cpp/utility/tuple/tie के साथ पूर्ण कोड उदाहरण देखने के लिए उपलब्ध है bool operator<(…)। दिलचस्प हिस्सा, के साथ काम करने के लिए बदल गया ==है:

#include <tuple>

struct S {
………
bool operator==(const S& rhs) const
    {
        // compares n to rhs.n,
        // then s to rhs.s,
        // then d to rhs.d
        return std::tie(n, s, d) == std::tie(rhs.n, rhs.s, rhs.d);
    }
};

std::tie सभी तुलना ऑपरेटरों के साथ काम करता है, और कंपाइलर द्वारा पूरी तरह से अनुकूलित किया जाता है।


-1

मैं मानता हूं, POD प्रकार की कक्षाओं के लिए तो कंपाइलर आपके लिए यह कर सकता है। हालाँकि जिसे आप सरल समझ सकते हैं वह कंपाइलर गलत हो सकता है। इसलिए प्रोग्रामर को इसे करने देना बेहतर है।

मेरे पास एक बार एक पीओडी मामला था जहां दो क्षेत्र अद्वितीय थे - इसलिए एक तुलना कभी भी सच नहीं मानी जाएगी। हालाँकि जो तुलना मुझे केवल पेलोड की तुलना में चाहिए थी - कुछ ऐसा जिसे कंपाइलर कभी समझ नहीं पाएगा या कभी खुद ही समझ सकता है।

इसके अलावा - वे लिखने के लिए लंबे समय तक नहीं करते हैं ?!

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