L'operatore << deve accettare esattamente un argomento


91

ah

#include "logic.h"
...

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

logic.cpp

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

Quando compilo, dice:

std :: ostream & logic :: operator << (std :: ostream &, A &) 'deve accettare esattamente un argomento.

Qual è il problema?

Risposte:


127

Il problema è che lo definisci all'interno della classe, che

a) significa che il secondo argomento è implicit ( this) e

b) non farà quello che vuoi che faccia, vale a dire estendere std::ostream.

Devi definirlo come una funzione libera:

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

8
Inoltre, lo dichiara come una funzione amico e lo definisce come una funzione membro.
asaelr

Come menzionato in en.cppreference.com/w/cpp/language/operators , "gli overload di operator >> e operator << che accettano uno std :: istream & o std :: ostream & come argomento della mano sinistra sono noti come insertion e operatori di estrazione. Poiché accettano il tipo definito dall'utente come argomento corretto (b in a @ b), devono essere implementati come non membri ".
Morteza

49

Una funzione amico non è una funzione membro, quindi il problema è che dichiari operator<<come amico di A:

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

quindi prova a definirlo come una funzione membro della classe logic

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

Sei confuso sul fatto che logicsia una classe o uno spazio dei nomi?

L'errore è dovuto al fatto che hai tentato di definire un membro operator<<prendendo due argomenti, il che significa che richiede tre argomenti incluso il thisparametro implicito . L'operatore può accettare solo due argomenti, in modo che quando scrivi a << bi due argomenti siano aeb .

Si vuole definire ostream& operator<<(ostream&, const A&)come non funzione di -Membro, sicuramente non come membro del logicdato che non ha nulla a che vedere con quella classe!

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

3

Mi sono imbattuto in questo problema con le classi basate su modelli. Ecco una soluzione più generale che ho dovuto usare:

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

Ora: * La mia funzione toString () non può essere inline se verrà nascosta in cpp. * Sei bloccato con del codice nell'intestazione, non sono riuscito a liberarmene. * L'operatore chiamerà il metodo toString (), non è inline.

Il corpo dell'operatore << può essere dichiarato nella clausola friend o al di fuori della classe. Entrambe le opzioni sono brutte. :(

Forse sto fraintendendo o mi manca qualcosa, ma la semplice dichiarazione anticipata del modello dell'operatore non si collega in gcc.

Funziona anche questo:

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

Penso che puoi anche evitare i problemi di templating che costringono le dichiarazioni nelle intestazioni, se usi una classe genitore che non è basata su modelli per implementare l'operatore << e usi un metodo virtuale toString ().


0

Se definisci operator<<come funzione membro, avrà una sintassi scomposta diversa rispetto a quella utilizzata per non membro operator<<. Un non membro operator<<è un operatore binario, dove un membro operator<<è un operatore unario.

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

Allora ... come li chiami davvero? Gli operatori sono strani in qualche modo, ti sfiderò a scrivere la operator<<(...)sintassi nella tua testa per dare un senso alle cose.

MyObj mo;

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

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

Oppure puoi provare a chiamare l'operatore binario non membro:

MyObj mo;

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

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

Non hai l'obbligo di fare in modo che questi operatori si comportino in modo intuitivo quando li trasformi in funzioni membro, potresti definire lo operator<<(int)spostamento a sinistra di alcune variabili membro se lo desideri, capire che le persone potrebbero essere un po 'colte alla sprovvista, non importa quanti commenti potresti Scrivi.

Quasi finalmente, ci possono essere momenti in cui entrambe le scomposizioni per una chiamata operatore sono valide, potresti finire nei guai qui e rimanderemo quella conversazione.

Infine, nota quanto potrebbe essere strano scrivere un operatore membro unario che dovrebbe assomigliare a un operatore binario (poiché puoi rendere gli operatori membri virtuali ..... anche tentando di non devolvere e correre lungo questo percorso ... )

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

    int value = 8;
};

Questa sintassi irriterà molti programmatori ora ...

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

Nota come coutè il secondo argomento della catena qui .... strano vero?

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.