473,698 Members | 2,047 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Interesting overload case

The following program illustrates an interesting effect of the way C++
resolves function overloading.

I have verified with a member of the C++ stardard committee that the output
shown is correct.

*************** *************** ***Program***** *************** ************

#include <iostream>
using std::cout;
using std::endl;

namespace test
{
enum test1 { testa=3, testb=4 };

std::ostream& operator<<(std: :ostream& os, test::test1 t)
{
os << " **** TEST1 **** ";
return os;
}

enum test2 { testc = 5, testd = 7 };
}

std::ostream& operator<<(std: :ostream& os, test::test2 t)
{
os << " **** TEST2 **** ";
return os;
}

test::test1 i(test::testa);
test::test2 j(test::testc);

namespace test
{
void testy()
{
cout << i << endl;
cout << j << endl;
}
}

int main()
{
cout << "Direct\n";
cout << i << endl;
cout << j << endl;
cout << "Indirect\n ";
test::testy();
return 0;
}

*************** *************** **Output******* *************** **********

Direct
**** TEST1 ****
**** TEST2 ****
Indirect
**** TEST1 ****
5
Jul 22 '05 #1
8 1574

"David Sachs" <sa***@fnal.gov > wrote in message
news:2K******** ************@co mcast.com...
The following program illustrates an interesting effect of the way C++
resolves function overloading.

I have verified with a member of the C++ stardard committee that the output shown is correct.

*************** *************** ***Program***** *************** ************

#include <iostream>
using std::cout;
using std::endl;

namespace test
{
enum test1 { testa=3, testb=4 };

std::ostream& operator<<(std: :ostream& os, test::test1 t)
{
os << " **** TEST1 **** ";
return os;
}

enum test2 { testc = 5, testd = 7 };
}

std::ostream& operator<<(std: :ostream& os, test::test2 t)
{
os << " **** TEST2 **** ";
return os;
}

test::test1 i(test::testa);
test::test2 j(test::testc);

namespace test
{
void testy()
{
cout << i << endl;
cout << j << endl;
}
}

int main()
{
cout << "Direct\n";
cout << i << endl;
cout << j << endl;
cout << "Indirect\n ";
test::testy();
return 0;
}

*************** *************** **Output******* *************** **********

Direct
**** TEST1 ****
**** TEST2 ****
Indirect
**** TEST1 ****
5


What is the cause of this?
Jul 22 '05 #2
"Dave" <be***********@ yahoo.com> wrote...

"David Sachs" <sa***@fnal.gov > wrote in message
news:2K******** ************@co mcast.com...
The following program illustrates an interesting effect of the way C++
resolves function overloading.

I have verified with a member of the C++ stardard committee that the

output
shown is correct.

*************** *************** ***Program***** *************** ************

#include <iostream>
using std::cout;
using std::endl;

namespace test
{
enum test1 { testa=3, testb=4 };

std::ostream& operator<<(std: :ostream& os, test::test1 t)
{
os << " **** TEST1 **** ";
return os;
}

enum test2 { testc = 5, testd = 7 };
}

std::ostream& operator<<(std: :ostream& os, test::test2 t)
{
os << " **** TEST2 **** ";
return os;
}

test::test1 i(test::testa);
test::test2 j(test::testc);

namespace test
{
void testy()
{
cout << i << endl;
cout << j << endl;
}
}

int main()
{
cout << "Direct\n";
cout << i << endl;
cout << j << endl;
cout << "Indirect\n ";
test::testy();
return 0;
}

*************** *************** **Output******* *************** **********

Direct
**** TEST1 ****
**** TEST2 ****
Indirect
**** TEST1 ****
5


What is the cause of this?


The cause is that when resolving which operator<< to use for
test::test2 _inside_ 'testy' function, the compiler is _not_
considering the global namespace, and cannot find the output
operator defined just above 'i' and 'j' objects. It has to
resort to finding a suitable std::ostream::o perator<< along
with converting an enum value into 'int'.

At least that's how I remember it.

Victor
Jul 22 '05 #3
Hello NG,

just to make some more mess I changed a little bit the code here:

// **** CODE CHANGES ****
namespace test
{
void testy()
{
operator<<(cout ,i) << endl;
cout << j << endl; // **** TEST2 **** in bcc and "5" in MSVC and g++
// operator<<(cout ,j) << endl;
// this one will not compile with MSVC 7.1, g++3.3.1
// but compiles with bcc 5.5.1: **** TEST2 ****
::operator<<(co ut,j) << endl; // **** TEST2 ****
// but this works how expected:
}
}

// **** CODE END ****

I used the direct call of the operator, and I think it is getting really
weird. Nicely enough the borland compiler does not agree with the others
(neither did it before the change). In fact I have promblems understanding
it :-(

1.) I my opinion the call

A << B;

should produce the same result like

operator<<(A,B) ;

If not, why and for what reason not? Is it still transparent then?

But:
MSVC7.1 and g++ will not compile

operator<<(cout ,j) << endl; // neither: std::operator<< (cout,j) << endl;

but both compile this line:

cout << j << endl;

which operator is called then?

2.) This one compiles and works fine

::operator<<(co ut,j) << endl;

does what it should do :-). Nice
Regards,
Patrick
Jul 22 '05 #4
"Patrick Kowalzick" <Pa************ ***@cern.ch> wrote in message
news:bq******** *@sunnews.cern. ch...
Hello NG,

just to make some more mess I changed a little bit the code here:

// **** CODE CHANGES ****
namespace test
{
void testy()
{
operator<<(cout ,i) << endl;
cout << j << endl; // **** TEST2 **** in bcc and "5" in MSVC and g++
// operator<<(cout ,j) << endl;
// this one will not compile with MSVC 7.1, g++3.3.1
// but compiles with bcc 5.5.1: **** TEST2 ****
::operator<<(co ut,j) << endl; // **** TEST2 ****
// but this works how expected:
}
}

// **** CODE END ****

I used the direct call of the operator, and I think it is getting really
weird. Nicely enough the borland compiler does not agree with the others
(neither did it before the change). In fact I have promblems understanding
it :-(

1.) I my opinion the call

A << B;

should produce the same result like

operator<<(A,B) ;

If not, why and for what reason not? Is it still transparent then?

But:
MSVC7.1 and g++ will not compile

operator<<(cout ,j) << endl; // neither: std::operator<< (cout,j) << endl;

but both compile this line:

cout << j << endl;

which operator is called then?

2.) This one compiles and works fine

::operator<<(co ut,j) << endl;

does what it should do :-). Nice
Regards,
Patrick

There actually is a subtle difference between

cout << j;

and

operator<<(cout ,j);

when the enem-specific form of operator<< is unavailable.

The first form (cout << j) will cause integral promotion of j. The C++
standard explicitly states that the enum will be converted to an int if
feasible, This feature allows displaying the numeric value of an enum if
operator<< is not overloaded for it.

The second form (explicit function call) will use whatever conversions of
the enum are feasible. For some C++ compilers such as g++, this will cause a
compile time error, because the forms

operator<<(ostr eam&, char)
operator<<(ostr eam&, unsigned char)
operator<<(ostr eam&, signed char)

are equally good, and better than anything else. A compiler that stores enum
s as int s would not notice this problem.
Jul 22 '05 #5
Dave wrote:
The following program illustrates an interesting effect of the way C++
resolves function overloading.

I have verified with a member of the C++ stardard committee that the

output
shown is correct.

*************** *************** ***Program***** *************** ************

#include <iostream>
using std::cout;
using std::endl;

namespace test
{
enum test1 { testa=3, testb=4 };

std::ostream& operator<<(std: :ostream& os, test::test1 t)
{
os << " **** TEST1 **** ";
return os;
}

enum test2 { testc = 5, testd = 7 };
}

std::ostream& operator<<(std: :ostream& os, test::test2 t)
{
os << " **** TEST2 **** ";
return os;
}

test::test1 i(test::testa);
test::test2 j(test::testc);

namespace test
{
void testy()
{
cout << i << endl;
cout << j << endl;
}
}

int main()
{
cout << "Direct\n";
cout << i << endl;
cout << j << endl;
cout << "Indirect\n ";
test::testy();
return 0;
}

*************** *************** **Output******* *************** **********

Direct
**** TEST1 ****
**** TEST2 ****
Indirect
**** TEST1 ****
5


What is the cause of this?
...


Inside 'test::testy' the name lookup for 'operator <<' works as follows:

1) Ordinary unqualified name lookup for 'operator<<' begins in namespace
'test' and immediately finds 'test::operator <<'.
2) Argument-dependent name lookup on the first argument finds a bunch of
'std::basic_ost ream<>::operato r<<' functions.
3) Argument-dependent name lookup on the second argument also finds
'test::operator <<'

Note that '::operator<<' is not found by name lookup. In this situation
overload resolution has no choice but to go with one of 'operator <<'
member functions of 'std::basic_ost ream<>', since 'test::operator <<'
cannot be used with value of type 'test2'.

Inside 'main' the name lookup for 'operator <<' works as follows:

1) Ordinary unqualified name lookup for 'operator<<' begins in global
scope and finds '::operator<<'.
2) Argument-dependent name lookup on the first argument finds a bunch of
'std::basic_ost ream<>::operato r<<' functions.
3) Argument-dependent name lookup on the second argument finds
'test::operator <<'

In this case overload resolution will choose '::operator<<' as the best
match. That explains the behavior of the program.

Note, that if you remove the declaration of 'test::operator <<', the
ordinary unqualified name lookup inside 'test::testy' will not stop
inside namespace 'test' and will continue into the global scope, where
it will find '::operator<<'. In this case, both 'test::testy' and 'main'
will output identical results.

--
Best regards,
Andrey Tarasevich

Jul 22 '05 #6
Andrey Tarasevich wrote:
...
Inside 'test::testy' the name lookup for 'operator <<' works as follows:

1) Ordinary unqualified name lookup for 'operator<<' begins in namespace
'test' and immediately finds 'test::operator <<'.
2) Argument-dependent name lookup on the first argument finds a bunch of
'std::basic_ost ream<>::operato r<<' functions.
3) Argument-dependent name lookup on the second argument also finds
'test::operator <<'

Note that '::operator<<' is not found by name lookup. In this situation
overload resolution has no choice but to go with one of 'operator <<'
member functions of 'std::basic_ost ream<>', since 'test::operator <<'
cannot be used with value of type 'test2'.

Inside 'main' the name lookup for 'operator <<' works as follows:

1) Ordinary unqualified name lookup for 'operator<<' begins in global
scope and finds '::operator<<'.
2) Argument-dependent name lookup on the first argument finds a bunch of
'std::basic_ost ream<>::operato r<<' functions.
3) Argument-dependent name lookup on the second argument finds
'test::operator <<'

In this case overload resolution will choose '::operator<<' as the best
match. That explains the behavior of the program.

Note, that if you remove the declaration of 'test::operator <<', the
ordinary unqualified name lookup inside 'test::testy' will not stop
inside namespace 'test' and will continue into the global scope, where
it will find '::operator<<'. In this case, both 'test::testy' and 'main'
will output identical results.


It is probably worth adding that in short this behavior is explained by
the simple fact that form the point of view of function 'test::testy'
'operator<<' declared inside namespace 'test' _hides_ global
'operator<<'. The global 'operator<<' can be "unhidden" by a
using-declaration in namespace 'test'

namespace test
{
using ::operator<<;

void testy()
{
cout << i << endl;
cout << j << endl;
}
}

In this case 'testy' will call the same 'operator <<' functions as
'main' does.

--
Best regards,
Andrey Tarasevich

Jul 22 '05 #7
Hello David,
There actually is a subtle difference between

cout << j;

and

operator<<(cout ,j);

when the enem-specific form of operator<< is unavailable.

The first form (cout << j) will cause integral promotion of j. The C++
standard explicitly states that the enum will be converted to an int if
feasible, This feature allows displaying the numeric value of an enum if
operator<< is not overloaded for it.

The second form (explicit function call) will use whatever conversions of
the enum are feasible. For some C++ compilers such as g++, this will cause a compile time error, because the forms

operator<<(ostr eam&, char)
operator<<(ostr eam&, unsigned char)
operator<<(ostr eam&, signed char)

are equally good, and better than anything else. A compiler that stores enum s as int s would not notice this problem.


This I got and later this day I try to find it in the Standard. But I do not
like it. For me it seems not to be transparent if there is such a difference
between the first and the second form.

And doesnt't this mean, that your original program may produce

Direct
**** TEST1 ****
**** TEST2 ****
Indirect
**** TEST1 ****
5

what is obviously right, but may produce as well with another compiler

Direct
**** TEST1 ****
**** TEST2 ****
Indirect
**** TEST1 ****
**** TEST2 ****

what could be a correct result as well. It just dependes on the type used
for enum. This would explain the differnt behavior of g++ (and MSVC)
compared to bcc.
Is this correct like this?

Regard,
Patrick
Jul 22 '05 #8
Patrick Kowalzick wrote:

And doesnt't this mean, that your original program may produce

Direct
**** TEST1 ****
**** TEST2 ****
Indirect
**** TEST1 ****
5

what is obviously right, but may produce as well with another compiler

Direct
**** TEST1 ****
**** TEST2 ****
Indirect
**** TEST1 ****
**** TEST2 ****

what could be a correct result as well. It just dependes on the type used
for enum. This would explain the differnt behavior of g++ (and MSVC)
compared to bcc.
Is this correct like this?
...


No, it doesn't depend on the type used for enum. The behavior of the
original program is explained by C++ name lookup rules. See my messages
in this thread for complete explanation.

--
Best regards,
Andrey Tarasevich

Jul 22 '05 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
1894
by: Chiller | last post by:
Ok, thanks to some good assistance/advice from people in this group I've been able to further develop my Distance class. Since previous posts I've refined my code to accept the unit measurement as a char rather than incorrectly representing it as an int. I've done this because I want to develop the class so that it will be able to convert between values, ie if I add 500 m to 1 km I'd like a correct result given in metres (1500 m in this...
9
1611
by: Mario Charest | last post by:
.. Hi, It's possible to overload the operator, but I wonder if it's possible to somehow overload and so forth. My goal would be to switch from static array declaration into something totaly dynamic with minimal change in the code. The following code
0
1255
by: Alex VanderWoude | last post by:
Okay, now I know how to directly reference a particular overload of a method in a cref. However, now I have the "opposite" problem. I want to directly reference the general summary page for all the overloaded methods. So far I've been able to do this by not mentioning any parameters in the method name, but in one case it seems to be failing and picking one of the overloads instead. For example, consider the following two overloads:...
17
2508
by: Chris | last post by:
To me, this seems rather redundant. The compiler requires that if you overload the == operator, you must also overload the != operator. All I do for the != operator is something like this: public static bool operator !=(MyType x, MyType y) { return !(x == y); } That way the == operator handles everything, and extra comparing logic isn't
2
1847
by: Michi Henning | last post by:
Hi, the following code produces an error on the second-last line: Interface Left Sub op() End Interface Interface Right Sub op(ByVal i As Integer)
9
2381
by: Tony | last post by:
I have an operator== overload that compares two items and returns a new class as the result of the comparison (instead of the normal bool) I then get an ambiguous operater compile error when I attempt to check to see if the object is null: "The call is ambiguous between the following methods or properties: 'TestObject.operator ==(TestObject, string)' and 'TestObject.operator ==(TestObject, TestObject)" Does anyone have any idea how to...
2
1865
by: xtrigger303 | last post by:
Hi to all, I was reading Mr. Alexandrescu's mojo article and I've a hard time understanding the following. Let's suppose I have: //code struct A {}; struct B : A {};
5
3695
by: jknupp | last post by:
In the following program, if the call to bar does not specify the type as <int>, gcc gives the error "no matching function for call to ‘bar(A&, <unresolved overloaded function type>)’". Since bar explicitly takes a pointer-to-member with no parameters, why is the lookup for the overloaded function not able to use the number of arguments to determine the appropriate function? Is there a relevant portion of the standard that governs the...
1
1744
by: fabian.lim | last post by:
Hi all, Im having a problem with my code. Im programming a vector class, and am trying to overload the () operator in 2 different situations. The first situation is to assign values, e.g. Y = X(1,2), the elements 1 and 2 of X gets assigned to Y. In this case, the operator () overload should create a copy that is unmodifiable. In the 2nd case, I want do assign values to elements 1 and 2, e.g. X(1,2) = Y. Then in this case, the values...
0
8674
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9026
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
8861
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
7723
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
6518
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
4366
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
3045
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
2328
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2001
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.