Question

Je suis en train d'écrire ma propre classe d'exploitation forestière et de l'utiliser comme un flux:

logger L;
L << "whatever" << std::endl;

Voici le code que j'ai commencé avec:

#include <iostream>

using namespace std;


class logger{
public:
    template <typename T>
    friend logger& operator <<(logger& log, const T& value);
};

template <typename T>
logger& operator <<(logger& log, T const & value) {
    // Here I'd output the values to a file and stdout, etc.
    cout << value;
    return log;
}

int main(int argc, char *argv[])
{
    logger L;
    L << "hello" << '\n' ; // This works
    L << "bye" << "alo" << endl; // This doesn't work
    return 0;
}

Mais je recevais une erreur en essayant de compiler, en disant qu'il n'y avait pas de définition pour l'opérateur << (lors de l'utilisation std :: endl):

pruebaLog.cpp:31: error: no match for ‘operator<<’ in ‘operator<< [with T = char [4]](((logger&)((logger*)operator<< [with T = char [4]](((logger&)(& L)), ((const char (&)[4])"bye")))), ((const char (&)[4])"alo")) << std::endl’

Alors, je l'ai essayé de surcharger l'opérateur << pour accepter ce genre de cours d'eau, mais ça me rend fou. Je ne sais pas comment le faire. J'ai loking à, par exemple, la définition de std :: endl au fichier d'en-tête de ostream et écrit une fonction avec cet en-tête:

logger& operator <<(logger& log, const basic_ostream<char,char_traits<char> >& (*s)(basic_ostream<char,char_traits<char> >&))

Mais pas de chance. J'ai essayé la même chose en utilisant des modèles au lieu d'utiliser directement char, et aussi essayé simplement en utilisant « const & ostream os », et rien.

Une autre chose qui me dérange est que, dans la sortie d'erreur, le premier argument pour l'opérateur << changements, il est parfois une référence à un pointeur, ressemble parfois à une double référence ...

Était-ce utile?

La solution

endl est une bête étrange. Il n'est pas une valeur constante. Il est en fait, de toutes choses, une fonction. Vous avez besoin d'une dérogation spéciale pour gérer l'application de endl:

logger& operator<< (logger& log, ostream& (*pf) (ostream&))
{
  cout << pf;
  return log;
}

accepte l'insertion d'une fonction qui prend une référence de ostream et renvoie une référence ostream. C'est ce que endl est.

Modifier En réponse à la question intéressante de FranticPedantic de « pourquoi ne peut pas en déduire le compilateur cela automatiquement? ». La raison en est que si vous fouillez encore plus profond, endl est en fait lui-même un template fonction. Il est défini comme suit:

template <class charT, class traits>
  basic_ostream<charT,traits>& endl ( basic_ostream<charT,traits>& os );

Autrement dit, il peut prendre toute sorte de ostream comme son entrée et de sortie. Le problème est donc pas que le compilateur ne peut pas en déduire que T const & pourrait être un pointeur de fonction, mais qu'il ne peut pas comprendre qui vous endl censé passer. La version de operator<< présenté basé sur un modèle la question accepterait un pointeur vers une fonction comme second argument, mais en même temps, le modèle de endl représente un infini ensemble de fonctions possibles, de sorte que le compilateur ne peut rien faire il significatif.

Fournir la surcharge spéciale du operator<< dont le second argument correspond à une spécifique instanciation du modèle de endl permet l'appel à résoudre.

Autres conseils

endl est un manipulateur IO, qui est un foncteur qui accepte un courant de référence, effectue une opération sur elle, et renvoie ce flux, également à titre de référence. cout << endl est équivalente à cout << '\n' << flush, où flush est un manipulateur qui vide la mémoire tampon de sortie.

Dans votre classe, il vous suffit d'écrire une surcharge pour cet opérateur:

logger& operator<<(logger&(*function)(logger&)) {
    return function(*this);
}

logger&(*)(logger&) est le type d'une fonction d'accepter et renvoyer une logger par référence. Pour écrire vos propres Manipulateurs, il suffit d'écrire une fonction qui correspond à cette signature, et l'ont effectuer une opération sur le flux:

logger& newline(logger& L) {
    return L << '\n';
}

Je crois que le problème est votre flux ne surcharge pas operator<< d'accepter une fonction qui a le même type que std::endl comme illustré dans cette réponse: std :: endl est de type inconnu en cas de surcharge opérateur <<

En C ++, il est le mémoire tampon de flux qui encapsule les E / S sous-jacent méchanisme. Le flux se résume uniquement les conversions à la chaîne, et la direction d'E / S.

Ainsi, vous devez utiliser l'une des classes de flux prédéfinis, plutôt que de faire votre propre. Si vous avez une nouvelle cible que vous voulez que votre E / S pour aller à (comme un journal système), ce que vous devez créer votre propre est tampon de flux (dérivé de std::streambuf).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top