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 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?
"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
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
"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.
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
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
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
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 This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics |
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...
|
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
|
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:...
|
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
|
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)
| |
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...
|
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 {};
|
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...
|
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...
|
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...
|
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...
| |
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...
|
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...
|
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...
|
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...
|
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
|
by: muto222 |
last post by:
How can i add a mobile payment intergratation into php mysql website.
| |
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...
| |