operator << moet precies één argument aannemen

a.h

#include "logic.h"
...
class A
{
friend ostream& operator<<(ostream&, A&);
...
};

logic.cpp

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

Als ik compileer, staat er:

std::ostream& logic::operator<<(std::ostream&, A&)’ moet precies één argument bevatten.

Wat is het probleem?


Antwoord 1, autoriteit 100%

Het probleem is dat je het binnen de klas definieert, wat

a) betekent dat het tweede argument impliciet is (this) en

b) het zal niet doen wat je wilt, namelijk std::ostreamuitbreiden.

Je moet het definiëren als een vrije functie:

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

Antwoord 2, autoriteit 37%

Een vriendfunctie is geen lidfunctie, dus het probleem is dat je operator<<aanduidt als vriend van a:

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

probeer het dan te definiëren als een lidfunctie van de klasse logic

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

Ben je niet zeker of logiceen klasse of een naamruimte is?

De fout is dat je hebt geprobeerd een lid operator<<te definiëren met twee argumenten, wat betekent dat er drie argumenten nodig zijn, inclusief de impliciete parameter this. De operator kan slechts twee argumenten aannemen, zodat wanneer u a << bde twee argumenten zijn aen b.

U wilt ostream& operator<<(ostream&, const A&)als een niet-lidfunctie, zeker niet als lid van logicaangezien het niets te maken heeft met die klas!

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

Antwoord 3, autoriteit 2%

Ik kwam dit probleem tegen met klassen met sjablonen.
Hier is een meer algemene oplossing die ik moest gebruiken:

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;
}

Nu:
* Mijn functie toString() kan niet inline zijn als deze in cpp wordt weggestopt.
* Je zit vast met een code in de header, ik kon er niet vanaf komen.
* De operator roept de methode toString() aan, deze is niet inline.

De hoofdtekst van de operator<< kan worden gedeclareerd in de vriendclausule of buiten de klasse. Beide opties zijn lelijk. 🙁

Misschien begrijp ik het verkeerd of mis ik iets, maar het doorsturen van de operatorsjabloon linkt niet in gcc.

Dit werkt ook:

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;
    }
}

Ik denk dat je ook de sjabloonproblemen kunt vermijden die declaraties in headers forceren, als je een bovenliggende klasse gebruikt die geen sjabloon heeft om operator<< te implementeren, en een virtuele toString()-methode gebruikt.


Antwoord 4

Als u operator<<definieert als een lidfunctie, heeft deze een andere ontlede syntaxis dan wanneer u een niet-lid operator<<gebruikt. Een niet-lid operator<<is een binaire operator, waar een lid operator<<een unaire operator is.

// 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;
}

Dus… hoe noem je ze echt? Operators zijn in sommige opzichten vreemd, ik daag je uit om de syntaxis van de operator<<(...)in je hoofd te schrijven om dingen logisch te maken.

MyObj mo;
// Calling the unary operator
mo << std::cout;
// which decomposes to...
mo.operator<<(std::cout);

Of u kunt proberen de binaire operator die geen lid is te bellen:

MyObj mo;
// Calling the binary operator
std::cout << mo;
// which decomposes to...
operator<<(std::cout, mo);

Je bent niet verplicht om deze operators intuïtief te laten gedragen wanneer je ze in lidfuncties maakt, je zou operator<<(int)kunnen definiëren om een lidvariabele naar links te verschuiven als je dat wilt, begrijp dat mensen misschien een beetje overrompeld worden, hoeveel reacties je ook schrijft.

Bijna als laatste kunnen er momenten zijn waarop beide ontledingen voor een telefoniste geldig zijn, u kunt hier in de problemen komen en we zullen dat gesprek uitstellen.

Ten slotte, merk op hoe vreemd het kan zijn om een unaire member-operator te schrijven die eruit zou moeten zien als een binaire operator (omdat je member-operators virtueel kunt maken… in een poging om niet te devolueren en dit pad af te lopen. …)

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

Deze syntaxis zal veel programmeurs nu irriteren….

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");

Merk op hoe de couthier het tweede argument in de keten is…. vreemd toch?


Antwoord 5

Overbelasting van operators omvat overbelasting van ledenfuncties en overbelasting van niet-ledenfuncties, die niet kunnen worden gecombineerd. https://condor.depaul.edu/ntomuro/courses/262/ notes/lecture3.html

Other episodes