Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Incorrect operator overload handling in .NET 2003

45 views
Skip to first unread message

Cliff

unread,
Sep 18, 2003, 5:55:29 PM9/18/03
to
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>

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.

If we move this functionality directly into the main function like so:

int main()
{
test* t = new test();
(*t) << "Test: " << "a string";
std::cout << t->str();
delete t;

return(0);
}

The compiler correctly identifies (const char *) as the proper overload for
the string "Test: " and the string prints out. As further evidence that
something is wrong, if the function test::addString is changed to:

void test::addString(const char* str)
{
std::string theString("Test: ");
(*this) << theString << str;
}

The code will not compile and it displays an error that no valid method for
type std::string can be found for the insertion operator. However, the code
will compile cleanly if the same thing is placed into main like this:

int main() {
test* t = new test();
std::string aString("Test: ");
(*t) << aString << "a string";
std::cout << t->str();
delete t;

return(0);
}

The final proof that the complier is confused came when we added an explicit
cast in test::addString to give:

void test::addString(const char* str) {
(static_cast<std::stringstream&>(*this)) << "Test: " << str;
}

With the cast in place, the complier properly maps "Test: " as a call to the
(const char*) overload, and requests to pass a std::string into the
insertion operator compile successfully.

Somehow, the use of (*this) inside a method of our class is not being
handled properly by the compiler. Has anyone else noticed this?

Cliff
<cliff_mccollum at hotmail dot com>


tom_usenet

unread,
Sep 19, 2003, 6:13:19 AM9/19/03
to
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.

Carl Daniel [VC++ MVP]

unread,
Sep 19, 2003, 10:31:43 AM9/19/03
to
Cliff 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.

Thanks to tom (see his post) for an excellent analysis. I agree that this
is a bug. You can consider it reported, so it should be fixed in a future
release.

-cd


Cliff

unread,
Sep 22, 2003, 4:42:24 PM9/22/03
to
Thanks Tom and Carl. I'm glad to hear that someone else agrees with our
analysis on this one. It's also nice to know that a fix will be forthcoming.

Cliff


"Carl Daniel [VC++ MVP]" <cpda...@nospam.mvps.org> wrote in message
news:OKBQArrf...@TK2MSFTNGP11.phx.gbl...

0 new messages