web-dev-qa-db-fra.com

l'opérateur << doit prendre exactement un argument

a.h

#include "logic.h"
...

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

logic.cpp

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

Quand je compile, ça dit:

std :: ostream & logic :: operator << (std :: ostream &, A &) 'doit prendre exactement un argument.

Quel est le problème?

72
As As

Le problème est que vous le définissez dans la classe, ce qui 

a) signifie que le deuxième argument est implicite (this) et 

b) il ne fera pas ce que vous voulez, à savoir étendre std::ostream

Vous devez le définir comme une fonction libre:

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

Une fonction ami n'est pas une fonction membre. Le problème est que vous déclarez operator<< en tant qu'ami de A:

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

puis essayez de le définir en tant que fonction membre de la classe logic

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

Êtes-vous confus quant à savoir si logic est une classe ou un espace de noms?

L'erreur est due au fait que vous avez essayé de définir un membre operator<< en prenant deux arguments, ce qui signifie qu'il faut trois arguments, y compris le paramètre implicite this. L'opérateur ne peut prendre que deux arguments. Ainsi, lorsque vous écrivez a << b, les deux arguments sont a et b.

Vous voulez définir ostream& operator<<(ostream&, const A&) en tant que fonction non - membre, certainement pas en tant que membre de logic car cela n’a rien à voir avec cette classe!

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

J'ai rencontré ce problème avec les classes basées sur des modèles ..__ Voici une solution plus générale que je devais utiliser:

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

Maintenant: * Ma fonction toString () ne peut pas être en ligne si elle doit être cachée dans cpp . * Vous êtes coincé avec un code dans l'en-tête, je ne pouvais pas m'en débarrasser . * L'opérateur appellera la méthode toString (), elle n'est pas en ligne.

Le corps de l'opérateur << peut être déclaré dans la clause friend ou en dehors de la classe. Les deux options sont laides. :(

Peut-être que je comprends mal ou que je manque quelque chose, mais déclarer simplement le modèle d'opérateur ne crée pas de lien dans gcc.

Cela fonctionne aussi:

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

Je pense que vous pouvez également éviter les problèmes de gabarit imposant les déclarations dans les en-têtes, si vous utilisez une classe parent qui n'est pas modélisée pour implémenter l'opérateur << et utilisez une méthode toString () virtuelle.

0
Dan Truong