Re: Automatic invocation of conversion function: operator std::ostream
Paul wrote:
I am working on a class for logging messages into a log file allowing for
the following syntax:
N::Log(N::ERR) << "Here goes the error message: integer = " << i << ",
long = " << l << std::endl;
I reasoned that the ?Log?, being a temporary object, would be ideal for
locking the file (std::ofstream) till the end of output [...]
?Log? was not meant to do anything but the handling of locking, so to
invoke real output I added ?operator std::ostream&()? to it that would
return a file stream (std::ofstream) declared at the namespace level,
and this was where I encountered a problem.
I can imagine one problem for sure: you have a temporary and are trying to
bind it to a non-const reference. Make it at least "operator ostream&()
const".
As far as I know, a compiler will try various conversion functions in the
hope of finding a meaningful interpretation of ?<<?.
Yes, but only in the second step. The first will be to find an operator<< or
a set of overloads, which is where this fails. You can see that it finds
the operator when you did this:
This code will not compile as written but the addition of these two
operators at the end of the N namespace:
namespace N {
// ...
std::ostream& operator <<(std::ostream& os, bool i)
{
return os.operator <<(i);
}
std::ostream& operator <<(std::ostream& os, const std::string& s)
{
return std::operator <<(os, s);
}
}
A simple using std::... would have done the job, too.
Anyhow, how about this sketch:
struct foo
{
~foo() { /*...lock, log, flush, unlock...*/ }
mutable std::ostringstream str;
};
template<typename T>
std::ostream&
operator<<( foo const& f, T const& t)
{ return f.str << t; }
std::ostream&
operator<<( foo const& f, std::ostream& (*fn)(std::osteam&)
{ return f.str << fn; }
std::ostream&
operator<<( foo const& f, std::basic_ios& (*fn)(std::basic_ios&)
{ return f.str << fn; }
For one
thing, having only added ...operator(..., bool) brings all others (int,
double) into the scope (see main()) (the std::string?s operator << is
defined separately, so has to be included also separately).
Note: << for std::string is a (free) function, while those for int and other
types are implemented as members of ostream.
(One other
strange thing that I noticed is the need to convert the first quoted
output explicitly to string (std::string(?Hello!?)), not required for
subsequent <<'s within the expression.)
I guess that this has to do with the fact that a char[n] operator<< is not
found and therefore neither the char const* nor the std::string versions
are considered.
I tried ?using std::operator <<;? and even ?using namespace std;?, all to
no avail.
Hmmm, I would have expected that to work, as said above.
Uli