S
Shriramana Sharma
Hello. Please consider the following code:
# include <iostream>
void foo ( int a, int b ) { std::cout << "foo(int,int)\n" ; }
void foo ( double a, double b ) { std::cout << "foo(double,double)\n" ; }
int main ()
{
int a = 2.2 ;
foo ( 1, 2 ) ;
foo ( 1, 2.2 ) ;
foo ( 2.2, 1 ) ;
foo ( 2.2, 2.2 ) ;
}
and the console session compiling it with GCC 4.7.4:
$ g++ -c overload-ambiguity.cpp
overload-ambiguity.cpp: In function ‘int main()’:
overload-ambiguity.cpp:8:17: error: call of overloaded ‘foo(int, double)’ is ambiguous
overload-ambiguity.cpp:8:17: note: candidates are:
overload-ambiguity.cpp:2:6: note: void foo(int, int)
overload-ambiguity.cpp:3:6: note: void foo(double, double)
overload-ambiguity.cpp:9:17: error: call of overloaded ‘foo(double, int)’ is ambiguous
overload-ambiguity.cpp:9:17: note: candidates are:
overload-ambiguity.cpp:2:6: note: void foo(int, int)
overload-ambiguity.cpp:3:6: note: void foo(double, double)
Clang 3.2 also makes the same complaints.
Initially I was surprised that the compiler flags the calls as ambiguous, since it seemed obvious that calling with arguments as (int,double) or (double,int) should only select the overload one that takes (double,double) since it is the only lossless one and not the lossy (int,int).
The explanation is possibly obvious from the fact that the compiler does not complain about int a = 2.2, meaning that the language permits an implicit cast of a double to an int (perhaps for C compatibility?). But at least when selecting overloads, one would expect the compiler to prefer a lossless overload to a lossy one. This is what D does:
import std.stdio ;
void foo ( int a, int b ) { writeln ( "foo(int,int)" ) ; }
void foo ( double a, double b ) { writeln ( "foo(double,double)" ) ; }
void main ()
{
// int a = 2.2 ;
foo ( 1, 2 ) ;
foo ( 1, 2.2 ) ;
foo ( 2.2, 1 ) ;
foo ( 2.2, 2.2 ) ;
}
compiles cleanly and outputs:
foo(int,int)
foo(double,double)
foo(double,double)
foo(double,double)
Of course, D doesn't allow the int a = 2.2 without a cast, but the overload mechanism is more sane in D. And I'm not trying to extol the virtues of D, but rather asking why C++ doesn't ensure that the lossless overload is selected over a lossy one, irrespective of whether the language permits an implicit lossy cast or not.
# include <iostream>
void foo ( int a, int b ) { std::cout << "foo(int,int)\n" ; }
void foo ( double a, double b ) { std::cout << "foo(double,double)\n" ; }
int main ()
{
int a = 2.2 ;
foo ( 1, 2 ) ;
foo ( 1, 2.2 ) ;
foo ( 2.2, 1 ) ;
foo ( 2.2, 2.2 ) ;
}
and the console session compiling it with GCC 4.7.4:
$ g++ -c overload-ambiguity.cpp
overload-ambiguity.cpp: In function ‘int main()’:
overload-ambiguity.cpp:8:17: error: call of overloaded ‘foo(int, double)’ is ambiguous
overload-ambiguity.cpp:8:17: note: candidates are:
overload-ambiguity.cpp:2:6: note: void foo(int, int)
overload-ambiguity.cpp:3:6: note: void foo(double, double)
overload-ambiguity.cpp:9:17: error: call of overloaded ‘foo(double, int)’ is ambiguous
overload-ambiguity.cpp:9:17: note: candidates are:
overload-ambiguity.cpp:2:6: note: void foo(int, int)
overload-ambiguity.cpp:3:6: note: void foo(double, double)
Clang 3.2 also makes the same complaints.
Initially I was surprised that the compiler flags the calls as ambiguous, since it seemed obvious that calling with arguments as (int,double) or (double,int) should only select the overload one that takes (double,double) since it is the only lossless one and not the lossy (int,int).
The explanation is possibly obvious from the fact that the compiler does not complain about int a = 2.2, meaning that the language permits an implicit cast of a double to an int (perhaps for C compatibility?). But at least when selecting overloads, one would expect the compiler to prefer a lossless overload to a lossy one. This is what D does:
import std.stdio ;
void foo ( int a, int b ) { writeln ( "foo(int,int)" ) ; }
void foo ( double a, double b ) { writeln ( "foo(double,double)" ) ; }
void main ()
{
// int a = 2.2 ;
foo ( 1, 2 ) ;
foo ( 1, 2.2 ) ;
foo ( 2.2, 1 ) ;
foo ( 2.2, 2.2 ) ;
}
compiles cleanly and outputs:
foo(int,int)
foo(double,double)
foo(double,double)
foo(double,double)
Of course, D doesn't allow the int a = 2.2 without a cast, but the overload mechanism is more sane in D. And I'm not trying to extol the virtues of D, but rather asking why C++ doesn't ensure that the lossless overload is selected over a lossy one, irrespective of whether the language permits an implicit lossy cast or not.