On Thu, 18 Sep 2003 21:55:29 GMT, "Cliff" <cl...
>We believe we have found a compiler error in C++ .NET 2003 using the
>supplied STL. In summary, the compiler incorrectly identifies the type of a
>subclass and fails to invoke the correct function overload. Here is the code
>that demonstrates the problem:
> #include <sstream>
> #include <iostream>
> #include <string>
Strictly speaking, to make it standard and portable, you need:
I agree that it should invoke the (const char*) overload, but the
reason for this is quite complex.
The problem appears to be that VC7 is failing to perform ADL properly
on the non-member operator set of a function when the member operator
exists in a base class. Here's what's meant to happen:
void test::addString(const char* str)
(*this) << str;
The expression "(*this) << str" is an operator expression. Operator
expressions have three forms of name lookup - member operator lookup,
non-member operator lookup and built in operator lookup. Here's what
should happen for the three:
Member operator lookup:
(*this).operator<<(str) is checked. std::basic_ostream::operator<< is
Non-member operator lookup:
operator<<(*this, str) is checked. Ordinary lookup finds nothing -
there are no operator<< functions at all in the global namespace.
Next, ADL is invoked. The namespace set of *this is that of itself
(the global namespace) plus that of its base classes (namespace
std)*****. The namespace set of str is empty, since it is a built-in.
So namespace std is searched for operator<<, and sure enough, some
candidate functions are found.
Built-in operator lookup:
No candidate functions are found.
The candiate functions are therefore:
All ostream::operator<< functions (including the void* one).
All std::operator<< functions so far declared (in particular, those in
<ostream> have been declared). (including the char const* one).
Obviously, std::operator<<(ostream&, char const*) is the best match,
and should be chosen unambiguously.
Now, MSVC7 only has the member ones to choose from because of the bug,
so the void* one is chosen as the best match.
In general VC7.1 has good name lookup skills (too good at times
(compared to what the standard requires) - they use fully recursive
searching of template parameter namespaces usually). However, I agree
with you that this is a bug.
***** This seems to be the mistake that MSVC7.1 is making - it isn't
searching the namespaces of base classes. This is why it works when
the cast to std::stringstream.