ऑपरेटर << बिल्कुल एक तर्क लेना चाहिए


94

आह

#include "logic.h"
...

class A
{
friend ostream& operator<<(ostream&, A&);
...
};

logic.cpp

#include "a.h"
...
ostream& logic::operator<<(ostream& os, A& a)
{
...
}
...

जब मैं संकलन करता हूं, तो यह कहता है:

std :: ostream and logic :: ऑपरेटर << (std :: ostream &, A &) 'को ठीक एक तर्क लेना चाहिए।

समस्या क्या है?

जवाबों:


132

समस्या यह है कि आप इसे कक्षा के अंदर परिभाषित करते हैं, जो

a) का अर्थ है दूसरा तर्क निहित है ( this) और

ख) यह वह नहीं करेगा जो आप चाहते हैं, अर्थात् विस्तार करें std::ostream

आपको इसे एक नि: शुल्क फ़ंक्शन के रूप में परिभाषित करना होगा:

class A { /* ... */ };
std::ostream& operator<<(std::ostream&, const A& a);

9
इसके अलावा, वह इसे एक फ्रेंड फंक्शन के रूप में घोषित करता है, और इसे एक सदस्य फंक्शन के रूप में परिभाषित करता है।
asaelr

जैसा कि en.cppreference.com/w/cpp/language/operators में उल्लेख किया गया है , "ऑपरेटर के अधिभार >> और ऑपरेटर << जो एक std लेते हैं :: istream और std :: ostream और बाएं हाथ के तर्क के रूप में सम्मिलन के रूप में जाने जाते हैं और निष्कर्षण ऑपरेटर
मोर्टेजा

49

एक दोस्त फ़ंक्शन एक सदस्य फ़ंक्शन नहीं है, इसलिए समस्या यह है कि आप operator<<एक मित्र के रूप में घोषित करते हैं A:

 friend ostream& operator<<(ostream&, A&);

फिर इसे कक्षा के सदस्य फ़ंक्शन के रूप में परिभाषित करने का प्रयास करें logic

 ostream& logic::operator<<(ostream& os, A& a)
          ^^^^^^^

क्या आप इस बारे में भ्रमित हैं कि logicकोई वर्ग या नामस्थान है?

त्रुटि इसलिए है क्योंकि आपने operator<<दो तर्क लेने वाले सदस्य को परिभाषित करने का प्रयास किया है, जिसका अर्थ है कि इसमें निहित तर्क सहित तीन तर्क हैं this। ऑपरेटर केवल दो तर्क ले सकता है, ताकि जब आप लिखते हैं a << bकि दो तर्क हैं aऔर b

आप ostream& operator<<(ostream&, const A&)एक गैर- प्रकार्य समारोह के रूप में परिभाषित करना चाहते हैं , निश्चित रूप से सदस्य के रूप में नहीं logicक्योंकि इसका उस वर्ग से कोई लेना-देना नहीं है!

std::ostream& operator<<(std::ostream& os, const A& a)
{
  return os << a.number;
}

3

मैं टेम्प्लेटेड कक्षाओं के साथ इस समस्या में भाग गया। यहाँ एक और सामान्य समाधान है जिसका मुझे उपयोग करना था:

template class <T>
class myClass
{
    int myField;

    // Helper function accessing my fields
    void toString(std::ostream&) const;

    // Friend means operator<< can use private variables
    // It needs to be declared as a template, but T is taken
    template <class U>
    friend std::ostream& operator<<(std::ostream&, const myClass<U> &);
}

// Operator is a non-member and global, so it's not myClass<U>::operator<<()
// Because of how C++ implements templates the function must be
// fully declared in the header for the linker to resolve it :(
template <class U>
std::ostream& operator<<(std::ostream& os, const myClass<U> & obj)
{
  obj.toString(os);
  return os;
}

अब: * My toString () फ़ंक्शन को इनलाइन नहीं किया जा सकता है अगर यह cpp में दूर जा रहा है। * आप हेडर में कुछ कोड के साथ फंस गए हैं, मैं इससे छुटकारा नहीं पा सका। * ऑपरेटर toString () विधि को कॉल करेगा, यह इनबिल्ड नहीं है।

ऑपरेटर का शरीर << कक्षा के बाहर या उसके दोस्त के खंड में घोषित किया जा सकता है। दोनों विकल्प बदसूरत हैं। :(

शायद मैं गलत समझ रहा हूँ या कुछ याद कर रहा हूँ, लेकिन बस आगे की घोषणा करने वाले ऑपरेटर टेम्पलेट gcc में लिंक नहीं करते हैं।

यह भी काम करता है:

template class <T>
class myClass
{
    int myField;

    // Helper function accessing my fields
    void toString(std::ostream&) const;

    // For some reason this requires using T, and not U as above
    friend std::ostream& operator<<(std::ostream&, const myClass<T> &)
    {
        obj.toString(os);
        return os;
    }
}

मुझे लगता है कि आप हेडर में घोषणाओं को लागू करने के लिए टेम्प्लेटिंग के मुद्दों से भी बच सकते हैं, यदि आप एक ऐसे अभिभावक वर्ग का उपयोग करते हैं जो ऑपरेटर को लागू करने के लिए टेम्प्लेट नहीं किया गया है, और वर्चुअल स्ट्रींग () विधि का उपयोग करता है।


0

यदि आप operator<<एक सदस्य फ़ंक्शन के रूप में परिभाषित करते हैं , तो यदि आप एक गैर-सदस्य का उपयोग करते हैं, तो इसकी तुलना में एक अलग विघटित सिंटैक्स होगा operator<<। एक गैर-सदस्य operator<<एक बाइनरी ऑपरेटर है, जहां एक सदस्य operator<<एक अपर ऑपरेटर है।

// Declarations
struct MyObj;
std::ostream& operator<<(std::ostream& os, const MyObj& myObj);

struct MyObj
{
    // This is a member unary-operator, hence one argument
    MyObj& operator<<(std::ostream& os) { os << *this; return *this; }

    int value = 8;
};

// This is a non-member binary-operator, 2 arguments
std::ostream& operator<<(std::ostream& os, const MyObj& myObj)
{
    return os << myObj.value;
}

तो .... आप उन्हें वास्तव में कैसे कहते हैं? ऑपरेटर कुछ मायनों में विषम हैं, मैं आपको चुनौती दूंगा operator<<(...)कि चीजों को बनाने के लिए अपने सिर में वाक्य रचना लिखें ।

MyObj mo;

// Calling the unary operator
mo << std::cout;

// which decomposes to...
mo.operator<<(std::cout);

या आप गैर-सदस्य बाइनरी ऑपरेटर को कॉल करने का प्रयास कर सकते हैं:

MyObj mo;

// Calling the binary operator
std::cout << mo;

// which decomposes to...
operator<<(std::cout, mo);

आपको इन कार्यों को operator<<(int)करने का कोई दायित्व नहीं है, जब आप उन्हें सदस्य के कार्यों में शामिल करते हैं, तो आप सहजता से व्यवहार कर सकते हैं, आप कुछ सदस्य चर को बाईं ओर शिफ्ट कर सकते हैं यदि आप चाहते हैं, तो समझें कि लोग थोड़े से परेशान हो सकते हैं, चाहे आप कितनी भी टिप्पणी करें। लिखो।

लगभग अंत में, ऐसे समय हो सकते हैं जहां ऑपरेटर कॉल के लिए दोनों डिकम्पोजिशन मान्य हैं, आप यहां परेशानी में पड़ सकते हैं और हम इस बातचीत को टाल देंगे।

अंत में, ध्यान दें कि एक अपर सदस्य ऑपरेटर को लिखना कितना अजीब हो सकता है जो कि एक बाइनरी ऑपरेटर की तरह दिखना है (जैसा कि आप सदस्य ऑपरेटरों को आभासी बना सकते हैं ..... यह भी इस मार्ग को नहीं बनाने और चलाने का प्रयास कर रहा है ...। )

struct MyObj
{
    // Note that we now return the ostream
    std::ostream& operator<<(std::ostream& os) { os << *this; return os; }

    int value = 8;
};

यह वाक्य रचना अब कई कोडर्स को परेशान करेगा ...।

MyObj mo;

mo << std::cout << "Words words words";

// this decomposes to...
mo.operator<<(std::cout) << "Words words words";

// ... or even further ...
operator<<(mo.operator<<(std::cout), "Words words words");

ध्यान दें कि coutयहाँ श्रृंखला में दूसरा तर्क कैसे है .... अजीब सही?

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