त्रुटि: xxx को 'इस' तर्क के रूप में उत्तीर्ण करने से क्वालीफायर छूट जाते हैं


456
#include <iostream>
#include <set>

using namespace std;

class StudentT {

public:
    int id;
    string name;
public:
    StudentT(int _id, string _name) : id(_id), name(_name) {
    }
    int getId() {
        return id;
    }
    string getName() {
        return name;
    }
};

inline bool operator< (StudentT s1, StudentT s2) {
    return  s1.getId() < s2.getId();
}

int main() {

    set<StudentT> st;
    StudentT s1(0, "Tom");
    StudentT s2(1, "Tim");
    st.insert(s1);
    st.insert(s2);
    set<StudentT> :: iterator itr;
    for (itr = st.begin(); itr != st.end(); itr++) {
        cout << itr->getId() << " " << itr->getName() << endl;
    }
    return 0;
}

पंक्ति में:

cout << itr->getId() << " " << itr->getName() << endl;

यह एक त्रुटि देता है कि:

../main.cpp:35: एरर: 'स्टूडेंट टीटी' को 'इंट स्टूडेंटटी :: गेटआईड ()' के तर्क के रूप में पास करना

../main.cpp:35: error: 'const' के रूप में 'const स्टूडेंट' पास करना 'std :: string स्टूडेंट :: getName ()' का तर्क क्वालिफायर

इस कोड में क्या गलत है? धन्यवाद!


13
आपके कोड स्निपेट में लाइन 35 कहां है?
सिलिको में

117
काश जीसीसी इस त्रुटि संदेश में सुधार करता, उदाहरण के लिए "क्वालीफायर को त्याग देता है" -> "
कांस्ट को

13
@ jfritz42: इस मामले के लिए भ्रामक होगा, जिसमें कहा गया हैvolatile
PlasmaHH

3
@PlasmaHH त्रुटि संदेश "ब्रेक कांस्ट शुद्धता" और "अस्थिर शुद्धता को तोड़ता है" में विभाजित हो जाएगा। अब, बहुत से लोग इस बारे में कुछ नहीं सोचेंगे कि यह सही है
केलथ

जवाबों:


523

में वस्तुओं के std::setरूप में संग्रहीत किया जाता है const StudentT। इसलिए जब आप ऑब्जेक्ट के getId()साथ कॉल करने का प्रयास करते हैं, तो constकंपाइलर एक समस्या का पता लगाता है, मुख्य रूप से आप एक नॉन-कास्ट मेंबर फंक्शन को कॉन्स्टेंट ऑब्जेक्ट पर कॉल कर रहे हैं, जिसकी अनुमति नहीं है क्योंकि नॉन-कॉस्ट मेंबर फंक्शंस NO PROMISE करते हैं ताकि ऑब्जेक्ट को संशोधित न किया जा सके; इसलिए संकलक एक सुरक्षित धारणा बनाने जा रहा है getId()जो वस्तु को संशोधित करने का प्रयास कर सकता है, लेकिन साथ ही, यह भी नोटिस करता है कि वस्तु कांस्टेबल है; इसलिए कास्ट ऑब्जेक्ट को संशोधित करने का कोई भी प्रयास एक त्रुटि होना चाहिए। इसलिए कंपाइलर एक त्रुटि संदेश उत्पन्न करता है।

समाधान सरल है: कार्यों को इस प्रकार बनाएं:

int getId() const {
    return id;
}
string getName() const {
    return name;
}

यह आवश्यक है क्योंकि अब आप कॉल कर सकते हैं getId()और getName()कांस्टेबल ऑब्जेक्ट्स पर:

void f(const StudentT & s)
{
     cout << s.getId();   //now okay, but error with your versions
     cout << s.getName(); //now okay, but error with your versions
}

एक विचार के रूप में, आपको निम्न के operator<रूप में लागू करना चाहिए :

inline bool operator< (const StudentT & s1, const StudentT & s2)
{
    return  s1.getId() < s2.getId();
}

नोट पैरामीटर अब constसंदर्भ हैं।


3
ऐसी स्पष्ट व्याख्या। धन्यवाद। लेकिन मुझे आपके अंतिम कोड स्निपेट के बारे में आश्चर्य है। फ़ंक्शन पैरामीटर में संदर्भ का उपयोग क्यों करें? const StudentT & s1, const StudentT & s2?
राफेल एडेल

2
@ राफेल एडेल: आप आवश्यक कॉपी से बचने के लिए संदर्भ का उपयोग करते हैं, और constक्योंकि फ़ंक्शन को ऑब्जेक्ट को संशोधित करने की आवश्यकता नहीं है, इसलिए constयह संकलन-समय पर लागू होता है।
नवाज

90

सदस्य कार्य जो कक्षा के उदाहरण को संशोधित नहीं करते हैं, उन्हें इस प्रकार घोषित किया जाना चाहिए const:

int getId() const {
    return id;
}
string getName() const {
    return name;
}

कभी भी आप "क्वालीफायर डिसाइडर्स" को देखते हैं, इसके बारे में बात कर रहे हैं constया volatile


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

@ महेश: हां, यह कांस्ट शुद्धता का हिस्सा है । मुझे यकीन नहीं है कि constयहाँ से कहाँ आ रहा है, लेकिन मुझे संदेह setहै कि आवृत्ति को बदलने से रोकने के लिए और इससे सेट को अमान्य कर रहा है।
फ्रेड लार्सन ने

@ महेश: मेरे कोड की समीक्षा पास नहीं करेगा। मेरे पास एक सहकर्मी है जो मुझे "कॉन्स्टेबल-काबिल" के रूप में संदर्भित करता है। 8v) foo obj;इसे const foo obj;एक बार बदलें और देखें कि क्या होता है। या ए का constसंदर्भ पास करें foo
फ्रेड लार्सन ने

3
@ महेश: ऐसा मैंने कहा है - यदि तत्वों setको बदल दिया जाता है, तो आदेश परेशान हो सकता है और फिर सेट अब मान्य नहीं है। ए में map, केवल कुंजी है const। में set, पूरी वस्तु वास्तव में महत्वपूर्ण है।
फ्रेड लार्सन

1
@ महेश: कास्ट आवश्यक हैं अन्यथा आप उन्हें कास्ट ऑब्जेक्ट के साथ नहीं बुला सकते। f()मेरे उत्तर में फ़ंक्शन देखें ।
नवाज

5

वास्तव में C ++ मानक (यानी C ++ 0x ड्राफ्ट ) कहता है (tnx to @Xeo & @Ben Voigt इशारा करते हैं कि मेरे लिए बाहर):

२३.२.४ सहयोगी कंटेनर
सेट और मल्टीसेट करने के लिए कुंजी प्रकार समान है। नक्शे के लिए और यह जोड़ी के बराबर है। एक सहयोगी कंटेनर में चाबियाँ अपरिवर्तनीय हैं। एक साहचर्य कंटेनर का
6 पुनरावृत्त द्विदिश पुनरावृत्ति श्रेणी का है। साहचर्य कंटेनरों के लिए जहां मूल्य प्रकार कुंजी प्रकार के समान है, दोनों पुनरावृत्ति और const_iterator निरंतर पुनरावृत्तियों हैं। यह अनिर्दिष्ट है कि क्या इटेटर और कॉन्स्टाइटर एक ही प्रकार के हैं या नहीं।

तो VC ++ 2008 Dinkumware कार्यान्वयन दोषपूर्ण है।


पुराना उत्तर:

आपको वह त्रुटि मिल गई क्योंकि std lib के कुछ कार्यान्वयन में set::iteratorवैसा ही है set::const_iterator

उदाहरण के लिए libstdc ++ (g ++ के साथ भेज दिया गया) में यह है ( संपूर्ण स्रोत कोड के लिए यहां देखें ):

typedef typename _Rep_type::const_iterator            iterator;
typedef typename _Rep_type::const_iterator            const_iterator;

और एसजीआई के डॉक्स में यह कहा गया है:

iterator       Container  Iterator used to iterate through a set.
const_iterator Container  Const iterator used to iterate through a set. (Iterator and const_iterator are the same type.)

दूसरी ओर VC ++ 2008 एक्सप्रेस आपके कोड को बिना शिकायत के संकलित करता है कि आप नॉन कॉन्स्टैंड मेथड्स पर कॉल कर रहे हैं set::iterator


2

आइए मैं एक अधिक विस्तार से उदाहरण देता हूं। नीचे की संरचना के अनुसार:

struct Count{
    uint32_t c;

    Count(uint32_t i=0):c(i){}

    uint32_t getCount(){
        return c;
    }

    uint32_t add(const Count& count){
        uint32_t total = c + count.getCount();
        return total;
    }
};

यहाँ छवि विवरण दर्ज करें

जैसा कि आप ऊपर देखते हैं, आईडीई (सीएलओएन), सुझाव देगा Non-const function 'getCount' is called on the const object । विधि add countमें को कास्ट ऑब्जेक्ट के रूप में घोषित किया जाता है, लेकिन विधि getCountकांस्ट विधि नहीं है, इसलिए count.getCount()सदस्यों में बदलाव हो सकता है count

नीचे के रूप में संकलन त्रुटि (मेरे संकलक में मुख्य संदेश):

error: passing 'const xy_stl::Count' as 'this' argument discards qualifiers [-fpermissive]

उपरोक्त समस्या को हल करने के लिए, आप कर सकते हैं:

  1. uint32_t getCount(){...}करने के लिए विधि बदलेंuint32_t getCount() const {...} । इसलिए count.getCount()सदस्यों को इसमें नहीं बदला जाएगा count

या

  1. परिवर्तन uint32_t add(const Count& count){...}करने के लिएuint32_t add(Count& count){...} । इसलिए countइसमें सदस्यों को बदलने के बारे में परवाह न करें।

जैसा कि आपको समस्या है, std :: सेट में ऑब्जेक्ट्स const स्टूडेंट के रूप में संग्रहीत किए जाते हैं, लेकिन विधि getId औरgetName नहीं हैं, इसलिए आप उपरोक्त त्रुटि देते हैं।

आप इस प्रश्न को 'कॉन्स्ट' का अर्थ एक वर्ग की घोषणा में अंतिम रूप से भी देख सकते हैं ? अधिक विस्तार के लिए।

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