Automatic invocation of conversion function: operator std::ostream
 
Hello,
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;
(where ???N??? is a namespace, N::ERR, severity, and ???i??? and ???l???, variables)
I reasoned that the ???Log???, being a temporary object, would be ideal for 
locking the file (std::ofstream) till the end of output (its destructor will 
only be invoked at the end of the full expression; obviously the 
multi-threaded library protects the stream but output can still be pre-empted 
after each ???<<???). ???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.
As far as I know, a compiler will try various conversion functions in the 
hope of finding a meaningful interpretation of ???<<???. This works without 
problems for built-in types (???operator int()??? does get invoked if an object 
that defines it finds itself to the left of ???<<??? in an expression) but so far 
I cannot say I have complete understanding of the behaviour of user-defined 
types in this scenario, nor could I find anything that would say the 
behaviour sought in this case is only limited to built-in types.
So, again, the behaviour I expected was:
1) N::Log(N::ERR): a temporary Log object is created; its constructor 
accepts, say, a single parameter indicating severity and locks the log file;
2) the compiler discovers that the object finds itself to the left of ???<<??? 
operator that is not defined in this class;
3) the compiler finds a conversion function and tries that: it returns 
std::ostream& for which the operator is defined;
4) with output complete, the temporary object is destroyed and its 
destructor unlocks the lock and releases the log file.
Here is the complete code save for the lock which is uniquely uninteresting:
#include <iostream>
#include <string>
namespace N {
    std::ostream& log_file(std::cout);
    class Log {
    public:
        enum Severity {ERR, INF, TRC};
        Log(Severity s) {}
        operator std::ostream &() { return log_file; }
    };
}
int main()
{
    std::cout << "Started.\n";
    N::Log(N::Log::INF) << std::string("string: ") << std::string("Hello!\n");
    N::Log(N::Log::INF) << std::string("int: ") << 1 << ", long: " << 1L << ", 
double: " << 1.5 << ", bool: " << true << std::endl;
    std::cout << "Press any key to exit...\n";
    char c;
    std::cin.get(c);
}
(Tried with both Visual Studio 2003 and 2005 with the same results.)
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);
    }
}
will actually make things work which gives me a glimmer of hope. 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). (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 tried ???using std::operator <<;??? and even ???using namespace std;???, all to no 
avail. Defining the Log class within the std namespace (namespace std { class 
Log {...}; //... } did not help, either, although in that case there was a 
warning that, say, ???int??? will be truncated (only the ...operator <<(..., 
bool) being defined).
Is there something with the syntax that I missed?
Thank you.