J'ai surchargé l'opérateur <<
template <Typename T>
UIStream& operator<<(const T);
UIStream my_stream;
my_stream << 10 << " heads";
Fonctionne mais:
my_stream << endl;
Donne une erreur de compilation:
erreur C2678: binaire '<<': aucun opérateur trouvé qui prend un opérande de gauche de type 'UIStream' (ou il n'y a pas de conversion acceptable)
Quel est le travail autour de la création de my_stream << endl
travail?
std::endl
est une fonction et std::cout
l'utilise en implémentant operator<<
pour prendre un pointeur de fonction avec la même signature que std::endl
.
Là, il appelle la fonction et transmet la valeur de retour.
Voici un exemple de code:
#include <iostream>
struct MyStream
{
template <typename T>
MyStream& operator<<(const T& x)
{
std::cout << x;
return *this;
}
// function that takes a custom stream, and returns it
typedef MyStream& (*MyStreamManipulator)(MyStream&);
// take in a function with the custom signature
MyStream& operator<<(MyStreamManipulator manip)
{
// call the function, and return it's value
return manip(*this);
}
// define the custom endl for this stream.
// note how it matches the `MyStreamManipulator`
// function signature
static MyStream& endl(MyStream& stream)
{
// print a new line
std::cout << std::endl;
// do other stuff with the stream
// std::cout, for example, will flush the stream
stream << "Called MyStream::endl!" << std::endl;
return stream;
}
// this is the type of std::cout
typedef std::basic_ostream<char, std::char_traits<char> > CoutType;
// this is the function signature of std::endl
typedef CoutType& (*StandardEndLine)(CoutType&);
// define an operator<< to take in std::endl
MyStream& operator<<(StandardEndLine manip)
{
// call the function, but we cannot return it's value
manip(std::cout);
return *this;
}
};
int main(void)
{
MyStream stream;
stream << 10 << " faces.";
stream << MyStream::endl;
stream << std::endl;
return 0;
}
Espérons que cela vous donne une meilleure idée de la façon dont ces choses fonctionnent.
J'ai fait ça pour résoudre mon problème, voici une partie de mon code:
template<typename T>
CFileLogger &operator <<(const T value)
{
(*this).logFile << value;
return *this;
}
CFileLogger &operator <<(std::ostream& (*os)(std::ostream&))
{
(*this).logFile << os;
return *this;
}
Main.cpp
int main(){
CFileLogger log();
log << "[WARNINGS] " << 10 << std::endl;
log << "[ERRORS] " << 2 << std::endl;
...
}
J'ai la référence ici http://www.cplusplus.com/forum/general/49590/
J'espère que cela peut aider quelqu'un.
Voir ici pour de meilleures façons d'étendre IOStreams. (Un peu dépassé, et adapté pour VC 6, donc vous devrez le prendre avec un grain de sel)
Le fait est que pour faire fonctionner les foncteurs (et endl, qui produit à la fois "\ n" et flush est un foncteur), vous devez implémenter l'interface ostream complète.
Les flux std
ne sont pas conçus pour être sous-classés car ils n'ont pas de méthodes virtuelles, donc je ne pense pas que vous irez trop loin avec cela. Vous pouvez essayer d'agréger un std :: ostream pour faire le travail.
Pour que endl
fonctionne, vous devez implémenter une version de operator<<
qui prend un pointeur vers une fonction car c'est ainsi que les manipulateurs tels que endl
sont gérés, c'est-à-dire.
UStream& operator<<( UStream&, UStream& (*f)( UStream& ) );
ou
UStream& UStream::operator<<( UStream& (*f)( UStream& ) );
Maintenant std::endl
est une fonction qui prend et retourne une référence à un std :: basic_ostream afin que cela ne fonctionne pas directement avec votre flux, vous devrez donc créer votre propre version qui appelle le std::endl
version dans votre std::iostream
.
Edit: On dirait que la réponse de GMan est meilleure. Il obtient std::endl
fonctionne aussi!
En plus de la réponse acceptée, avec C++ 11, il est possible de surcharger operator<<
pour le type:
decltype(std::endl<char, std::char_traits<char>>)