On Thu, 18 Sep 2003 21:55:29 GMT, "Cliff" <cl
...@example.com> wrote:
>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:
#include <ostream>
> class test : public std::stringstream
> {
> public:
> void addString(const char* str);
> };
> void test::addString(const char* str)
> {
> (*this) << "Test: " << str;
> }
> int main()
> {
> test* t = new test();
> t->addString("a string");
> std::cout << t->str();
> delete t;
> return(0);
> }
>When this code is run, inside the test::addString method, the stream
>insertion operator is called for the string "Test:". This *should* invoke
>the overload for (const char *). However, it actually invokes the overload
>for (void *) causing the address of the string to be printed out instead.
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
found.
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.
Tom
***** 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.