না == অপারেটর সি ++ তে স্ট্রাক্টের তুলনা করার সময় পাওয়া গেল


100

নিম্নলিখিত কাঠামোর দুটি উদাহরণের তুলনা করে, আমি একটি ত্রুটি পেয়েছি:

struct MyStruct1 {
    MyStruct1(const MyStruct2 &_my_struct_2, const int _an_int = -1) :
        my_struct_2(_my_struct_2),
        an_int(_an_int)
    {}

    std::string toString() const;

    MyStruct2 my_struct_2;
    int an_int;
};

ত্রুটিটি হ'ল:

ত্রুটি C2678: বাইনারি '==': কোনও অপারেটর পাওয়া যায় নি যা 'মাইপ্রজ :: মাইস্ট্রাক্ট 1' টাইপের বাম-হাতের অপারেণ্ড নেয় (বা কোনও গ্রহণযোগ্য রূপান্তর নেই)

কেন?

উত্তর:


131

সি ++ এ, structএর ডিফল্টরূপে উত্পন্ন তুলনা অপারেটর নেই। আপনার নিজের লিখতে হবে:

bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
    return /* your comparison code goes here */
}

21
@ জোনাথন: সি ++ কেন জানবে যে আপনি কীভাবে structসমতার জন্য নিজের তুলনা করতে চান ? এবং যদি আপনি সহজ উপায় চান, memcmpআপনার স্ট্রাইকগুলিতে পয়েন্টার থাকে না এমন সবসময় থাকে।
জিও

12
@ শিও: memcmpনন-পিওডি সদস্যদের (যেমন std::string) এবং প্যাডযুক্ত কাঠামোর সাথে ব্যর্থ হয় ।
ফ্রেডওভারফ্লো

16
@ জোনাথান আমি জানি "আধুনিক" ভাষাগুলি একটি ==অপারেটরকে --- একটি শব্দার্থক শব্দ সরবরাহ করে যা প্রায়শই চায় না। (এবং তারা এটিকে ওভাররাইড করার কোনও মাধ্যম সরবরাহ করে না, তাই আপনাকে সদস্য ফাংশনটি ব্যবহার করতে হবে)। আমি জানি "আধুনিক" ভাষাগুলিও মূল্য শব্দার্থবিদ্যা সরবরাহ করে না, সুতরাং আপনি পয়েন্টারগুলি উপযুক্ত না হওয়া সত্ত্বেও বাধ্য করতে বাধ্য হন।
জেমস কানজে

4
@ জনাথন কেসগুলি কোনও নির্দিষ্ট প্রোগ্রামের মধ্যে অবশ্যই আলাদা হয়। সত্তা অবজেক্টের জন্য, জাভা দ্বারা প্রদত্ত সমাধানটি খুব ভালভাবে কাজ করে (এবং অবশ্যই আপনি সি ++ তে ঠিক একই জিনিসটি করতে পারেন --- এটি সত্তা অবজেক্টগুলির জন্য এমনকি আইডেম্যাটিক সি ++)। প্রশ্ন মান মান সম্পর্কে কি করা উচিত। সি operator=সামঞ্জস্যের কারণে সি ++ একটি ডিফল্ট সরবরাহ করে (যদিও এটি প্রায়শই ভুল কাজ করে)। সি সামঞ্জস্যের operator==অবশ্য কোনও প্রয়োজন হয় না । বিশ্বব্যাপী, আমি সি ++ জাভা যা করে তার চেয়ে বেশি পছন্দ করে। (আমি সি # জানি না, তাই সম্ভবত এটি আরও ভাল।)
জেমস কান্জে

9
কমপক্ষে এটি সম্ভব হওয়া উচিত= default !
ব্যবহারকারী 36251515

99

সি ++ ২০ প্রবর্তিত ডিফল্ট তুলনাগুলি, "দ্য স্পেসশিপ"operator<=> , যা আপনাকে সংকলক-উত্পাদিত </ <=/ ==/ !=/ >=/ এবং / অথবা >অপারেটরদের / স্পষ্ট / নিষ্পাপ (?) প্রয়োগের সাথে অনুরোধ করার অনুমতি দেয় ...

auto operator<=>(const MyClass&) const = default;

... তবে আপনি আরও জটিল পরিস্থিতির জন্য এটি কাস্টমাইজ করতে পারেন (নীচে আলোচনা করা হয়েছে)। ভাষা প্রস্তাবের জন্য এখানে দেখুন , এতে ন্যায্যতা এবং আলোচনা রয়েছে। এই উত্তরটি সি ++ 17 এবং তার আগের এবং আপনার কখনই প্রয়োগকরণ কাস্টমাইজ করা উচিত অন্তর্দৃষ্টি জন্য প্রাসঙ্গিক থেকে যায় operator<=>....

এটি ইতিমধ্যে এটি ইতিমধ্যে মানক না করা কিছুটা অস্বাস্থ্যকর বলে মনে হতে পারে তবে প্রায়শই স্ট্রাইক / ক্লাসগুলির তুলনা থেকে বাদ দেওয়ার জন্য কিছু ডেটা সদস্য থাকে (যেমন কাউন্টার, ক্যাশেড ফলাফল, ধারক ক্ষমতা, শেষ অপারেশন সাফল্য / ত্রুটি কোড, কার্সার) হিসাবে পাশাপাশি অগণিত বিষয়গুলি সম্পর্কে সিদ্ধান্ত নেওয়ার পাশাপাশি সীমাবদ্ধ নয়:

  • কোন ক্ষেত্রগুলি প্রথমে তুলনা করতে হবে, উদাহরণস্বরূপ, কোনও নির্দিষ্ট intসদস্যের তুলনা করলে খুব দ্রুত 99% অসম বস্তু মুছে ফেলা হতে পারে, তবে map<string,string>সদস্যের প্রায়শই অভিন্ন প্রবেশাধিকার থাকতে পারে এবং তুলনা করার জন্য তুলনামূলকভাবে ব্যয়বহুল হতে পারে - যদি রানটাইমের সময় মানগুলি লোড হয় তবে প্রোগ্রামারটির অন্তর্দৃষ্টি থাকতে পারে সংকলক সম্ভবত না
  • স্ট্রিংগুলির সাথে তুলনা করার ক্ষেত্রে: কেস সংবেদনশীলতা, সাদা স্থান এবং পৃথককারীগুলির সমতুল্যতা, সম্মেলনগুলি পালানোর ...
  • স্পেস / ডাবল তুলনা করার সময় নির্ভুলতা
  • NaN ভাসমান পয়েন্টের মানগুলি সমান বিবেচনা করা উচিত কিনা
  • পয়েন্টার বা পয়েন্ট-টু-ডেটা তুলনা (এবং যদি পরবর্তীটি হয় তবে কীভাবে পয়েন্টারগুলি অ্যারেতে হয় এবং কীভাবে কতগুলি অবজেক্ট / বাইটের তুলনা প্রয়োজন তা জানতে হবে)
  • অরসোর্টার্ড কনটেইনার (যেমন vector, list) তুলনা করার সময় অর্ডারটি গুরুত্বপূর্ণ কিনা এবং যদি তাই হয় তবে ভার্সেসের তুলনা করার আগে সেগুলি যথাস্থানে বাছাই করা ঠিক আছে কিনা প্রতিবারের সাথে তুলনা করার পরে অস্থায়ীভাবে বাছাই করার জন্য অতিরিক্ত মেমরি ব্যবহার করে
  • বর্তমানে কয়টি অ্যারে উপাদান বৈধ মান ধরেছে যা তুলনা করা উচিত (কোথাও কোনও আকার বা প্রেরণিকা আছে?)
  • কোন সদস্যের unionসাথে তুলনা করা
  • নরমালাইজেশন: উদাহরণস্বরূপ, তারিখের প্রকারগুলি মাসের বাইরে বা মাসের মাসের বাইরে-বা সীমানা / ভগ্নাংশের অবজেক্টের 6/8 তম থাকতে পারে এবং অন্যটিতে 3/4 অংশ থাকতে পারে, যা কার্য সম্পাদনের কারণে তারা সংশোধন করে অলসভাবে একটি পৃথক স্বাভাবিককরণের পদক্ষেপ সহ; তুলনার আগে আপনাকে একটি সাধারণীকরণকে ট্রিগার করতে হবে কিনা তা সিদ্ধান্ত নিতে হতে পারে
  • দুর্বল পয়েন্টারগুলি বৈধ না হলে কী করবেন
  • কীভাবে এমন সদস্য এবং ঘাঁটিগুলি পরিচালনা করবেন যেগুলি তাদের প্রয়োগ operator==করে না (তবে তাদের থাকতে পারে compare()বা operator<অথবা গ্রাহকরা থাকতে পারে str()...)
  • অন্যান্য থ্রেডগুলি আপডেট করতে পারে এমন ডেটা পড়ার / তুলনা করার সময় অবশ্যই কোন লকগুলি নেওয়া উচিত

সুতরাং, আপনার ত্রুটিযুক্ত কাঠামোর জন্য তুলনাটির অর্থ কী হওয়া উচিত তা স্পষ্টভাবে চিন্তা না করা অবধি ত্রুটি থাকা এক ধরণের সুন্দর কারণ এটি সংকলন করতে দেওয়া কিন্তু রান-টাইমে আপনাকে কোনও অর্থবহ ফলাফল দেয় না

যে সমস্ত বলেন, এটা ++ যদি সি আপনি বলা যাক ভালো হতে চাই bool operator==() const = default;যখন কোন কাজের সিদ্ধান্ত চাই একটি "সরল" সদস্য-বাই-সদস্য ==পরীক্ষা ছিল ঠিক আছে। একই জন্য !=। প্রদত্ত একাধিক সদস্য / ঘাঁটি, "ডিফল্ট" <, <=, >, এবং >=বাস্তবায়নের যদিও আশাহীন বলে মনে হচ্ছে - ঘোষণা এর সম্ভব কিন্তু খুব হতে চেয়েছি, সদস্য ক্রম জন্য শর্তগুলো পরস্পরবিরোধী (ঘাঁটি সদস্যদের সামনে অগত্যা হচ্ছে দ্বারা গোষ্ঠীবদ্ধ দেওয়া অসম্ভাব্য ক্রম ভিত্তিতে ক্যাসকেডিং নির্ভরযোগ্য ব্যবহারের আগে অ্যাক্সেসযোগ্যতা, নির্মাণ / ধ্বংস)। আরও ব্যাপকভাবে দরকারী হতে, সি ++ এর জন্য পছন্দগুলির গাইডেন্স করার জন্য একটি নতুন ডেটা মেম্বার / বেস অ্যানোটেশন সিস্টেমের প্রয়োজন হবে - এটি স্ট্যান্ডার্ডে থাকা দুর্দান্ত জিনিস হবে যদিও আদর্শভাবে এএসটি ভিত্তিক ব্যবহারকারী সংজ্ঞায়িত কোড জেনারেশনের সাথে মিলিত হবে ... আমি আশা করি এটা '

সমতা অপারেটরগুলির সাধারণ বাস্তবায়ন

একটি প্রশংসনীয় বাস্তবায়ন

এটি সম্ভবত যুক্তিসঙ্গত এবং দক্ষ বাস্তবায়ন হতে পারে:

inline bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
    return lhs.my_struct2 == rhs.my_struct2 &&
           lhs.an_int     == rhs.an_int;
}

মনে রাখবেন, এই একটি প্রয়োজন operator==জন্য MyStruct2খুব।

নীচে আপনার মাইস্ট্রাক্ট 1 এর সুনির্দিষ্টতার আলোচনার শিরোনামে এই প্রয়োগের প্রভাবগুলি এবং বিকল্পগুলি আলোচনা করা হয়েছে ।

==, <,> <= ইত্যাদির একটি ধারাবাহিক পন্থা

std::tupleআপনার নিজের শ্রেণীর উদাহরণগুলির সাথে তুলনা করা সহজতর করার তুলনা অপারেটরগুলি - কেবল std::tieতুলনার পছন্দসই ক্ষেত্রে ক্ষেত্রগুলিতে রেফারেন্সগুলি তৈরি করতে ব্যবহার করুন । এখান থেকে আমার উদাহরণ জেনারেল করা :

inline bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
    return std::tie(lhs.my_struct2, lhs.an_int) ==
           std::tie(rhs.my_struct2, rhs.an_int);
}

inline bool operator<(const MyStruct1& lhs, const MyStruct1& rhs)
{
    return std::tie(lhs.my_struct2, lhs.an_int) <
           std::tie(rhs.my_struct2, rhs.an_int);
}

// ...etc...

আপনি যখন "নিজস্ব" হন (যেমন সম্পাদনা করতে পারেন, কর্পোরেট এবং তৃতীয় পক্ষের libs সহ একটি উপাদান) আপনি যে শ্রেণীর সাথে তুলনা করতে চান এবং বিশেষত returnবিবৃতি থেকে ফাংশন রিটার্নের ধরণের জন্য সি ++ 14 এর প্রস্তুতি সহ , এটি প্রায়শই ভাল হয় " আপনি যে শ্রেণীর সাথে তুলনা করতে সক্ষম হতে চান তার সাথে সদস্য ফাংশনটি টাই করুন:

auto tie() const { return std::tie(my_struct1, an_int); }

তারপরে উপরের তুলনাগুলি এটিকে সহজতর করুন:

inline bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
    return lhs.tie() == rhs.tie();
}

আপনি যদি তুলনা অপারেটরগুলির একটি পূর্ণাঙ্গ সেট চান, তবে আমি আপনাকে অপারেটরদের বুস্ট করার পরামর্শ দেব (অনুসন্ধান করুন less_than_comparable)। যদি এটি কোনও কারণে অনুপযুক্ত হয়, তবে আপনি সমর্থন ম্যাক্রোগুলি (অনলাইন) এর ধারণাটি পছন্দ করতে বা পছন্দ করতে পারেন :

#define TIED_OP(STRUCT, OP, GET_FIELDS) \
    inline bool operator OP(const STRUCT& lhs, const STRUCT& rhs) \
    { \
        return std::tie(GET_FIELDS(lhs)) OP std::tie(GET_FIELDS(rhs)); \
    }

#define TIED_COMPARISONS(STRUCT, GET_FIELDS) \
    TIED_OP(STRUCT, ==, GET_FIELDS) \
    TIED_OP(STRUCT, !=, GET_FIELDS) \
    TIED_OP(STRUCT, <, GET_FIELDS) \
    TIED_OP(STRUCT, <=, GET_FIELDS) \
    TIED_OP(STRUCT, >=, GET_FIELDS) \
    TIED_OP(STRUCT, >, GET_FIELDS)

... যে পরে একটি লা ব্যবহার করা যেতে পারে ...

#define MY_STRUCT_FIELDS(X) X.my_struct2, X.an_int
TIED_COMPARISONS(MyStruct1, MY_STRUCT_FIELDS)

(সি ++ ১৪ টি সদস্যের টাই সংস্করণ এখানে )

আপনার মাইস্ট্রাক্ট 1 এর নির্দিষ্টকরণের আলোচনা

সদস্যের তুলনায় একটি ফ্রি-স্ট্যান্ডিং সরবরাহের পছন্দটিতে জড়িত রয়েছে operator==()...

ফ্রিস্ট্যান্ডিং বাস্তবায়ন

আপনি একটি আকর্ষণীয় সিদ্ধান্ত গ্রহণ আছে। যেহেতু আপনার ক্লাসটি স্পষ্টভাবে একটি থেকে তৈরি করা যেতে পারে MyStruct2, একটি মুক্ত স্থায়ী / সদস্যবিহীন bool operator==(const MyStruct2& lhs, const MyStruct2& rhs)ফাংশন সমর্থন করবে ...

my_MyStruct2 == my_MyStruct1

... প্রথমে MyStruct1থেকে একটি অস্থায়ী তৈরি করে my_myStruct2, তারপর তুলনা করে doing এটি অবশ্যই MyStruct1::an_intকনস্ট্রাক্টরের ডিফল্ট প্যারামিটার মানকে সেট করবে -1। কিনা আপনি অন্তর্ভুক্ত উপর নির্ভর করে an_intআপনার বাস্তবায়নে তুলনা operator==, একটি MyStruct1শক্তি বা সমান তুলনা নাও হতে পারে MyStruct2নিজেই যে এর সমান তুলনা MyStruct1'র my_struct_2সদস্য! তদ্ব্যতীত, একটি অস্থায়ী তৈরি MyStruct1করা একটি খুব অকার্যকর অপারেশন হতে পারে, কারণ এটি বিদ্যমান my_struct2সদস্যকে অস্থায়ীভাবে অনুলিপি করতে জড়িত , কেবল তুলনার পরে এটিকে ফেলে দিতে। (অবশ্যই, আপনি সেই নির্মাতা তৈরি করে বা MyStruct1এর জন্য explicitডিফল্ট মানটি সরিয়ে তুলনার জন্য এইগুলির অন্তর্নিহিত নির্মাণকে আটকাতে পারেন an_int))

সদস্য বাস্তবায়ন

আপনি যদি একটি অন্তর্নিহিত নির্মাণ এড়াতে চান তাহলে MyStruct1A থেকে MyStruct2তুলনা অপারেটর সদস্য ফাংশন করুন:

struct MyStruct1
{
    ...
    bool operator==(const MyStruct1& rhs) const
    {
        return tie() == rhs.tie(); // or another approach as above
    }
};

constকীওয়ার্ডটি নোট করুন - কেবল সদস্য প্রয়োগের জন্য প্রয়োজনীয় - সংকলককে পরামর্শ দেয় যে বস্তুর তুলনা করে সেগুলি সংশোধন করে না, সুতরাং constবস্তুগুলিতে অনুমতি দেওয়া যেতে পারে ।

দৃশ্যমান উপস্থাপনা তুলনা

কখনও কখনও আপনি যে ধরণের তুলনা চান তা পাওয়ার সহজতম উপায় হতে পারে ...

    return lhs.to_string() == rhs.to_string();

... যা প্রায়শই খুব ব্যয়বহুল - যারা stringবেদনাদায়কভাবে তৈরি করা হয়েছিল কেবল তা ফেলে দেওয়ার জন্য! ভাসমান পয়েন্ট মানগুলির সাথে প্রকারের জন্য, দৃশ্যমান উপস্থাপনাগুলির তুলনা করার অর্থ প্রদর্শিত সংখ্যার সংখ্যাটি সহনশীলতা নির্ধারণ করে যার মধ্যে প্রায় সমান মানগুলি তুলনার সময় সমান হিসাবে বিবেচিত হয়।


ঠিক আছে, আসলে তুলনা অপারেটরদের <,>, <=,> = এর জন্য শুধুমাত্র <প্রয়োগ করতে হবে। বাকিগুলি অনুসরণ করে এবং সেগুলি বাস্তবায়নের চেয়ে স্বয়ংক্রিয়ভাবে উত্পন্ন হতে পারে তার অর্থ ভিন্ন রূপে কার্যকর করার কোনও অর্থবহ উপায় নেই। এগুলি আপনাকে নিজেই প্রয়োগ করতে হবে তা উদ্ভট।
আন্দ্রে

@ আঁদ্রে: আরও প্রায়ই একটি ম্যানুয়ালি লিখিত int cmp(x, y)বা compareফাংশন একটি নেতিবাচক মান ফিরে x < yএবং সমতার জন্য, 0 জন্য একটি ইতিবাচক মান x > yভিত্তি হিসাবে ব্যবহার করা হয় <, >, <=, >=, ==, এবং !=; এই সমস্ত অপারেটরকে ক্লাসে ইনজেক্ট করতে সিআরটিপি ব্যবহার করা খুব সহজ। আমি নিশ্চিত যে আমি একটি পুরানো উত্তরে বাস্তবায়ন পোস্ট করেছি, তবে এটি দ্রুত খুঁজে পেল না।
টনি ডেলরয়

@TonyD নিশ্চিত করুন যে আপনি তা করতে পারে, কিন্তু এটা ঠিক যেমন সহজ বাস্তবায়ন হয় >, <=এবং >=পদ <। আপনি পারে এছাড়াও বাস্তবায়ন ==এবং !=যে ভাবে, কিন্তু যে সাধারণত একটি খুব দক্ষ বাস্তবায়নের আমি হবে। যদি এই সমস্তটির জন্য কোনও সিআরটিপি বা অন্যান্য কৌশলগুলির প্রয়োজন না হয় তবে চমৎকার হবে তবে মানকটি কেবল এই অপারেটরদের স্বতঃ-উত্পাদনকে ম্যান্ডেট করে যদি ব্যবহারকারীর দ্বারা স্পষ্টভাবে সংজ্ঞায়িত না হয় এবং <সংজ্ঞায়িত হয়।
আন্দ্রে

@ আন্দ্রে: এটি কারণ ==এবং !=সম্ভবত দক্ষতার সাথে এটি প্রকাশ করে না <যে সমস্ত কিছুর জন্য তুলনা ব্যবহার করা সাধারণ। "এটা চমৎকার হবে কোন CRTP বা অন্যান্য ঠাট প্রয়োজন হত যদি" - সম্ভবত, কিন্তু তারপর CRTP সহজেই অন্যান্য অপারেটরদের প্রচুর (জেনারেট করতে ব্যবহার করা যেতে পারে যেমন, bitwise |, &, ^থেকে |=, &=এবং ^=; + - * / %তাদের নিয়োগ ফরম থেকে; বাইনারি -ইউনারী অস্বীকৃতি থেকে +) - এই থিমটিতে এমন অনেকগুলি সম্ভাব্য কার্যকর প্রকরণ যা কেবল একটি সুন্দর স্বেচ্ছাসেবী স্লাইসের জন্য একটি ভাষা বৈশিষ্ট্য সরবরাহ করে তা বিশেষভাবে মার্জিত নয়।
টনি ডেলরয়

আপনি কি এক প্লাজেবল প্রয়োগে এমন একটি সংস্করণ যুক্ত std::tieকরতে চান যা একাধিক সদস্যের তুলনা করতে ব্যবহার করে?
নাথানঅলিভার

16

আপনি স্পষ্টভাবে সংজ্ঞায়িত করতে প্রয়োজন operator ==জন্য MyStruct1

struct MyStruct1 {
  bool operator == (const MyStruct1 &rhs) const
  { /* your logic for comparision between "*this" and "rhs" */ }
};

এই ধরণের 2 টি অবজেক্টের জন্য এখন == তুলনা বৈধ।


11

সি ++ 20 থেকে শুরু করে, এটি ডিফল্ট তুলনা অপারেটরদের (একটি সম্পূর্ণ সেট যোগ করা সম্ভব হওয়া উচিত ==, <=একটি ঘোষণা করে একটি বর্গ, ইত্যাদি) ডিফল্ট তিনপথ তুলনা অপারেটর ( "মহাকাশযান" অপারেটর), এরকম:

struct Point {
    int x;
    int y;
    auto operator<=>(const Point&) const = default;
};

একটি কমপ্লায়েন্ট সি ++ 20 সংকলক সহ, মাই স্ট্রাক্ট 1 এবং মাই স্ট্রাক্ট 2 এ সেই লাইন যুক্ত করা সমতা তুলনার অনুমতি দেওয়ার জন্য যথেষ্ট হতে পারে, ধরে নিয়ে মাই স্ট্রাক্ট 2 এর সংজ্ঞাটি সামঞ্জস্যপূর্ণ।


2

সি বা সি ++ তে স্ট্রাক্টের তুলনা কাজ করে না। পরিবর্তে ক্ষেত্রের সাথে তুলনা করুন।


2

ডিফল্ট স্ট্রাক্টগুলিতে ==অপারেটর নেই। আপনাকে নিজের প্রয়োগটি লিখতে হবে:

bool MyStruct1::operator==(const MyStruct1 &other) const {
    ...  // Compare the values, and return a bool result.
  }

0

বাক্সের বাইরে, == অপারেটর কেবল আদিমদের জন্য কাজ করে। আপনার কোডটি কাজ করতে পেতে আপনাকে আপনার স্ট্রাক্টের জন্য == অপারেটরটি ওভারলোড করতে হবে।


0

কারণ আপনি আপনার স্ট্রাক্টের জন্য তুলনা অপারেটর লেখেন নি। সংকলকটি এটি আপনার জন্য উত্পন্ন করে না, সুতরাং আপনি যদি তুলনা করতে চান তবে আপনাকে এটি নিজে লিখতে হবে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.