c++ - relacionales - sobrecarga de operadores unarios
std:: endl es de tipo desconocido al sobrecargar al operador<< (6)
Sobrecargué al operador <<
template <Typename T>
UIStream& operator<<(const T);
UIStream my_stream;
my_stream << 10 << " heads";
Funciona pero
my_stream << endl;
Da error de compilación:
error C2678: binario ''<<'': no se ha encontrado ningún operador que tome un operando de la izquierda del tipo ''UIStream'' (o no hay una conversión aceptable)
¿Cuál es el trabajo para hacer que my_stream << endl
funcione?
Además de la respuesta aceptada, con C ++ 11 es posible sobrecargar el operator<<
para el tipo:
decltype(std::endl<char, std::char_traits<char>>)
El problema es que std::endl
es una plantilla de función, como su operador <<
es. Entonces cuando escribes:
my_stream << endl;
le gustará que el compilador deduzca los parámetros de plantilla para el operador así como para endl
. Esto no es posible
Por lo tanto, debe escribir sobrecargas adicionales de plantilla <<
para trabajar con manipuladores. Su prototipo se verá así:
UIStream& operator<<(UIStream& os, std::ostream& (*pf)(std::ostream&));
(hay otros dos, reemplazando std::ostream
por std::basic_ios<char>
y std::ios_base
, que también debe proporcionar si desea permitir todos los manipuladores) y su implementación será muy similar a la de tus plantillas De hecho, es tan similar que puede usar su plantilla para la implementación de esta manera:
typedef std::ostream& (*ostream_manipulator)(std::ostream&);
UIStream& operator<<(UIStream& os, ostream_manipulator pf)
{
return operator<< <ostream_manipulator> (os, pf);
}
Una nota final, a menudo escribir un streambuf
personalizado, es a menudo una mejor manera de lograr lo que uno trata de lograr aplicando a la técnica que está utilizando.
Hice esto para resolver mi problema, aquí está parte de mi código:
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;
...
}
Obtuve la referencia aquí http://www.cplusplus.com/forum/general/49590/
Espero que esto pueda ayudar a alguién.
Los flujos std
no están diseñados para ser subclasificados ya que no tienen métodos virtuales, así que no creo que llegues demasiado lejos con eso. Sin embargo, puedes intentar agregar un std :: ostream para hacer el trabajo.
Para hacer que endl
funcione, es necesario implementar una versión del operator<<
que tome un puntero a función, ya que así es como se manejan los manipuladores como endl
es decir,
UStream& operator<<( UStream&, UStream& (*f)( UStream& ) );
o
UStream& UStream::operator<<( UStream& (*f)( UStream& ) );
Ahora std::endl
es una función que toma y devuelve una referencia a std :: basic_ostream para que no funcione directamente con la transmisión, por lo que deberá crear su propia versión que llame a la versión std::endl
en su agregado std::iostream
.
Editar: Parece que la respuesta de GMan es mejor. Él se vuelve std::endl
también!
Vea here para mejores formas de extender IOStreams. (Un poco desactualizado, y adaptado para VC 6, por lo que tendrá que tomarlo con un grano de sal)
El punto es que para que los funtores funcionen (y endl, que tanto salidas "/ n" como rubores es un funtor), necesitas implementar la interfaz completa de ostream.
std::endl
es una función y std::cout
utiliza implementando el operator<<
para tomar un puntero de función con la misma firma que std::endl
.
Allí, llama a la función y reenvía el valor de retorno.
Aquí hay un ejemplo de código:
#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;
}
Espero que esto te dé una mejor idea de cómo funcionan estas cosas.