Pre-requisite: Function Overloading in C++
Function overloading is a feature of object-oriented programming where two or more functions can have the same name but different parameters. When a function name is overloaded with different jobs it is called Function Overloading. Two or more functions are said to be overloaded if they differ in any of the following-
- The number of arguments.
- Order of arguments.
- Type of arguments.
In Function overloading, sometimes a situation can occur when the compiler is unable to choose between two correctly overloaded functions. This situation is said to be ambiguous.
Ambiguous statements are error-generating statements and the programs containing ambiguity will not compile. Automatic type conversions are the main cause of ambiguity. In C++, the type of argument that is used to call the function is converted into the type of parameters defined by the function.
Let’s understand ambiguity through a few examples.
Call of overloaded function is ambiguous
Example 1: Call of overloaded ‘test(char)’ is ambiguous
How this ambiguity occurs:
Below is the C++ program to demonstrate the ambiguity.
C++
#include <iostream>
using
namespace
std;
void
test(
float
f)
{
cout <<
"Overloaded Function with float "
<<
"parameter being called"
;
}
void
test(
double
d)
{
cout <<
"Overloaded Function with double "
<<
"parameter being called"
;
}
int
main()
{
test(
'a'
);
return
0;
}
Output:
prog.cpp: In function ‘int main()’:
prog.cpp:25:11: error: call of overloaded ‘test(char)’ is ambiguous
test(‘a’);
^
prog.cpp:8:6: note: candidate: void test(float)
void test(float f)
^
prog.cpp:15:6: note: candidate: void test(double)
void test(double d)
^
Why ambiguity occurs:
When there is no exact type match, the compiler looks for the closest match. The closest match for “test(‘a’);” will be “void test(int a)”, since it is not present, void test(double d) and void (float f)will cause ambiguity. Both are valid conversions. This confusion causes an error message to be displayed and prevents the program from compiling.
Note:
According to the C language specification, any integer type shorter than int, for example, bool, char, short are implicitly converted to int.
A char fits into an int without overflowing or losing precision, which explains the first code. But an int doesn’t fit into a char (overflow), double (lack of precision), or int* (incompatible type).
How to resolve ambiguity:
There are two ways to resolve this ambiguity:
- Typecast char to float.
- Remove either one of the ambiguity generating functions float or double and add overloaded function with an int type parameter.
Solution 1: Typecast char to float
Below is the C++ program to demonstrate how typecasting char to float resolves the issue.
C++
#include <iostream>
using
namespace
std;
void
test(
float
f)
{
cout <<
"Overloaded Function with float "
<<
"parameter being called"
;
}
void
test(
double
d)
{
cout <<
"Overloaded Function with double "
<<
"parameter being called"
;
}
int
main()
{
test((
float
)(
'a'
));
return
0;
}
Output
Overloaded Function with float parameter being called
Solution 2: Remove either one of the ambiguity generating functions float or double and add overloaded function with an int type parameter.
Below is the C++ program to demonstrate how adding an overloading function with an int type parameter can resolve the ambiguity in the above code.
C++
#include <iostream>
using
namespace
std;
void
test(
int
f)
{
cout <<
"Overloaded Function with "
<<
"int type parameter called"
;
}
void
test(
double
d)
{
cout <<
"Overloaded Function with "
<<
"double type parameter called"
;
}
int
main()
{
test(
'a'
);
return
0;
}
Output
Overloaded Function with int type parameter called
Example 2: Call of overloaded ‘test(float)’ is ambiguous
How this ambiguity occurs:
Below is the C++ program to demonstrate what will happen in the scenario when the type of float value is used to call the overloaded function and there is no function with the float or double parameters.
C++
#include <iostream>
using
namespace
std;
void
test(
int
f)
{
cout <<
"Overloaded Function with "
<<
"int type parameter called"
;
}
void
test(
long
l)
{
cout <<
"Overloaded Function with "
<<
"long type parameter called"
;
}
int
main()
{
test(2.5f);
return
0;
}
Output:
prog.cpp: In function ‘int main()’:
prog.cpp:25:12: error: call of overloaded ‘test(float)’ is ambiguous
test(2.5f);
^
prog.cpp:8:6: note: candidate: void test(int)
void test(int f)
^
prog.cpp:15:6: note: candidate: void test(long int)
void test(long d)
^
Why ambiguity occurs:
The above code will throw an error because the test(2.5f) function call will look for float function if not present it is only promoted to double, but there is no function definition with double or float type of parameter.
Unless explicitly specified all floating-point literals are automatically of type double in C++. In this ambiguity, the variable of a float type is implicitly converted to double type and if there is no overloaded function of float or double type and the function is called with a float value then the program will throw an error.
Note:
The float is converted to double under the following situations:
- The float is an argument to a function call, corresponding to a parameter type double in a function prototype.
- A binary operator has double and float as two argument types.
- A conditional operator has double and float as a second and third operand.
- The float value is cast to double.
- The float value is assigned to double.
How to resolve ambiguity:
There are two ways to resolve the ambiguity-
- Typecast float to int.
- Remove either one of the ambiguity generating functions int or long and add overloaded function with a double type parameter.
Solution 1: Typecast float to int
Below is the C++ program to demonstrate how typecasting float to int resolves the issue.
C++
#include <iostream>
using
namespace
std;
void
test(
int
f)
{
cout <<
"Overloaded Function with "
<<
"int type parameter called"
;
}
void
test(
long
l)
{
cout <<
"Overloaded Function with "
<<
"long type parameter called"
;
}
int
main()
{
test((
int
)(2.5f));
return
0;
}
Output
Overloaded Function with int type parameter called
Solution 2: Remove either one of the ambiguity generating functions int or long and add overloaded function with a double type parameter.
Below is the C++ program to demonstrate how to resolve this ambiguity by adding an overloaded function with double type parameters.
C++
#include <iostream>
using
namespace
std;
void
test(
double
d)
{
cout <<
"Overloaded Function with "
<<
"double type parameter called"
;
}
void
test(
long
l)
{
cout <<
"Overloaded Function with "
<<
"long type parameter called"
;
}
int
main()
{
test(2.5f);
return
0;
}
Output
Overloaded Function with double type parameter called
Call of overloaded function with different number of arguments
Redefinition of ‘void test(int, int) function:
Let’s look at another ambiguity scenario where ambiguity occurs when it is two-parameter and one of the parameters has a default value set.
C++
#include <iostream>
using
namespace
std;
void
test(
int
i)
{
cout <<
"Overloaded function with "
<<
"one int parameter called "
<< endl;
cout << i;
}
void
test(
int
i,
int
j = 5)
{
int
sum;
sum = i + j;
cout <<
"Overloaded function with "
<<
"two int parameter called "
<< endl;
cout << sum;
}
int
main()
{
test(10, 11);
test(10);
return
0;
}
Output:
prog.cpp: In function ‘void test(int, int)’:
prog.cpp:17:6: error: redefinition of ‘void test(int, int)’
void test(int i, int j = 5)
^
prog.cpp:8:6: note: ‘void test(int, int)’ previously defined here
void test(int i, int j)
^
prog.cpp: In function ‘int main()’:
prog.cpp:35:10: error: too few arguments to function ‘void test(int, int)’
test(10);
^
prog.cpp:8:6: note: declared here
void test(int i, int j)
^
Why ambiguity occurs:
Here, in the unambiguous call statement test(10, 11) two arguments are specified, therefore there is no ambiguity. In the ambiguous call statement test(10), the compiler gets confused about whether to call the first function test() which takes one argument or to call the second test() function with two arguments out of which one is the default. This causes the program to throw an error.
How to resolve the ambiguity:
One solution to resolve the ambiguity is to remove the default value from the overloaded function with two int parameters. Below is the C++ program to demonstrate the above approach-
C++
#include <iostream>
using
namespace
std;
void
test(
int
i)
{
cout <<
"Overloaded function with "
<<
"one int parameter called "
<< endl;
cout << i << endl;
}
void
test(
int
i,
int
j)
{
int
sum;
sum = i + j;
cout <<
"Overloaded function with "
<<
"two int parameter called "
<< endl;
cout << sum << endl;
}
int
main()
{
test(10, 11);
test(10);
return
0;
}
Output
Overloaded function with two int parameter called 21 Overloaded function with one int parameter called 10
Time Complexity: O(1)
Auxiliary Space: O(1)
Problem:
You are trying to compile a C/C++ program but you see an error message like
srcmain.cpp:127:21: error: call of overloaded 'abs(uint32_t)' is ambiguous
that refers to a line like
long timedelta = abs(millis() - startTime);
Solution:
Cast the argument to abs()
to int
or another suitable type:
long timedelta = abs(((int)millis() - startTime));
That should fix the error.
The reason for the error message is that millis()
and startTime
are both unsigned integers (uint32_t
), hence their difference (millis() - startTime
) is also an uint32_t
. However it makes no sense to compute the abs()
of an unsigned integer since the absolute value of an absolute-value integer is always the same as the input argument.
Then, the compiler tries to cast the uint32_t
to any type that is compatible with abs()
, like int
, float
, double
, … but it doesn’t know which of those types is the correct one to cast it to.
By saying call of overloaded abs()
the compiler is trying to tell you that there are multBiple argument types with which you can call abs()
, including int
, float
, double
, … – a function with the same name but different argument types is called overloaded.
By saying is ambiguous
, the compiler is telling you that it doesn’t know which of those variants of abs()
it should call.
Note that the compiler does not know that all overloaded variants of abs()
fundamentally do the same thing, so it won’t just cast your uint32_t
into any arbitrary type. Also, there are tiny details in how the abs()
variants work – for example, float abs(float)
will do a different calculation compared to double abs(double)
since it computes with 32-bit floating point numbers (float
) as opposed to 64-bit floating point numbers (double
).
Hence, the compiler can’t just assume that they are all the same and it doesn’t matter which one it calls, even though they represent the same underlying mathematical operation
In the Function overloading tutorial, we have seen how to overload a function by providing the same function with different number, type or sequence of arguments. However some of you may get an error, particularly when dealing with floats. Lets take an example to understand what I am talking about.
In this example we are overloading a function sum. While overloading we gave different types of arguments in both the functions so its a valid case of overloading but still we get compilation error in this program.
#include<iostream> using namespace std; int sum(int a,int b){ return a+b; } int sum(float a, float b){ return a+b; } int main(){ cout<<sum(1.3, 2.7); return 0; }
Output:
error: call to 'sum' is ambiguous
The reason is that while calling sum function we passed floating point value to function, assuming that compiler would treat them as float but the fact is that the compiler treat all the floating points numbers as double until unless you specially specify them as float by providing a “f” suffix at their end.
So to solve the issue we need to suffix the arguments with “f” like this:
#include<iostream> using namespace std; int sum(int a,int b){ return a+b; } int sum(float a, float b){ return a+b; } int main(){ cout<<sum(1.3f, 2.7f); return 0; }
Output:
4
lily19 0 / 0 / 0 Регистрация: 30.09.2016 Сообщений: 11 |
||||
1 |
||||
14.10.2016, 14:18. Показов 11024. Ответов 6 Метки нет (Все метки)
помогите пожалуйста, выдает ошибку. не знаю где
__________________
0 |
Programming Эксперт 94731 / 64177 / 26122 Регистрация: 12.04.2006 Сообщений: 116,782 |
14.10.2016, 14:18 |
6 |
7275 / 6220 / 2833 Регистрация: 14.04.2014 Сообщений: 26,871 |
|
14.10.2016, 14:53 |
2 |
Работает. Где ошибка?
0 |
lily19 0 / 0 / 0 Регистрация: 30.09.2016 Сообщений: 11 |
||||
14.10.2016, 14:57 [ТС] |
3 |
|||
я писала в dev и в онлайн компиляторе в c++shell. ошибка была показана тут:
0 |
0 / 0 / 0 Регистрация: 13.10.2016 Сообщений: 5 |
|
14.10.2016, 14:59 |
4 |
abs замени на fabs
0 |
lily19 0 / 0 / 0 Регистрация: 30.09.2016 Сообщений: 11 |
||||
14.10.2016, 19:48 [ТС] |
5 |
|||
мелочь, а важно..спасибо.мне помогло)) Добавлено через 4 часа 43 минуты
0 |
Падаван С++ 447 / 261 / 89 Регистрация: 11.11.2014 Сообщений: 916 |
|
14.10.2016, 19:59 |
6 |
z= D||E||F; , какой ответ вы ожидаете в этой строке ?
0 |
GbaLog- |
14.10.2016, 20:12
|
Не по теме:
я писала
я все сделал Кто же Вы? :scare:
0 |
- Forum
- General C++ Programming
- Call of overloaded constructor is ambigu
Call of overloaded constructor is ambiguous
When I try to instantiate objects of class Foo in main() of foo.cpp, I keep getting errors about how the call to the overloaded constructor is ambiguous. The compiler seems to not be able to tell between a non-reference parameter input like int num
and a lreference parameter input like int &num
. It also seems to not be able to tell between a non-reference parameter input and a rreference parameter input like int &&num
. Why would this be? If the passed element is not any kind of reference, doesn’t it make a copy of the original element and then pass the copy? Passing by lreference would mean that a pointer to the original element is passed and that the user could manipulate the original element by manipulating the reference, right? Same goes with rreferences? Why is the compiler confused when I clearly sent it something that has to be moved from one place in memory to another without creating a copy?
Relevant error readout and code that I referenced are listed below:
compiler readout
|
|
foo.cpp
|
|
lvalue and rvalue reference parameters provide a means to overload functions on the value categories of their arguments.
Consider these two overloads of
f
:
|
|
An expression like
f(e)
calls the first overload when
e
is an lvalue expression; it calls the second overload when
e
is an rvalue expression.
This third overload of
f
does not care about the value category of
e
.
void f(int) {}
Mixing the three functions leads to ambiguity. Which function should be called when the argument is a rvalue?
Last edited on
So because the third overload does not care about the value category, is there a way to represent a non-reference value without causing ambiguity?
How could these not be ambiguous?
|
|
@dutch- I understand why it would cause ambiguity. See my question above your comment.
Then your question is senseless.
is there a way to represent a non-reference value without causing ambiguity?
References are not objects, and the type of an expression is never a reference. Given the declaration
int& x = y;
The type of the expression
x
is
int
.
What behavior do you want to see, and why do you think you want to see it?
In one of the constructors, I want a copied value to be passed in as a parameter that isn’t referencing the original value. int &x, for example, would pass a pointer to the callee that can then have its original value modified or assigned to some other value. int &&x would be an rvalue that doesn’t have its own assigned place in memory. Neither of these methods of passing some sort of value, from what I understand, are able to pass a value that is a copy of the original value but that can’t affect the original value if the parametrized value is assigned something new.
My above comment was not meant to imply that I never was asking about why the compiler found ambiguities. I was asking about that and @mbozzi clarified it for me. Then I had a question about how I would represent a parameratized value that would be a copy of another value that cannot be altered by the callee. A reference to a value WOULD be able to be alterted by the callee as the parameratized input is pointing to an already existing place in memory. Changing the data of that parameratized input would change what data was held at that same memory address.
Last edited on
If a copy is needed, just pass-by-value?
void f(int) {}
I think, the ambiguity is because you have overloaded constructors, if you just remove other two constructors (&),(&&), then you can achieve what you are saying.
Given we have may varieties of constructors, I think we have to stick to what’s best for us.
Neither of these methods of passing some sort of value, from what I understand, are able to pass a value that is a copy of the original value but that can’t affect the original value if the parametrized value is assigned something new.
Pardon?
If you don’t want the original objects to be changed, just declare the references const:
Foo(const int& val1, const int& val2):
Anyway that’s not a problem in your code, since you anyway copy them into the class prorperties:
num1{ val1 }, num2{ val2 }
The compiler can tell pointers and not pointers apart, if you really, really, really need that (I’m not suggesting it’s a good idea):
|
|
Output:
Arguments passed by copy Arguments passed by copy Arguments passed by pointers
@Enoizat- I didn’t think about «const». That qualifier would definitely accomplish what I want it to since it would eliminate ambiguity and serve to provide a non-alterable copy.
Topic archived. No new replies allowed.
Я не знаком с шаблонами. Я только начал изучать это. Почему я получаю ошибки в следующей программе?
#include <iostream>
#include <string>
using std::cout;
using std::string;
template<class C>
C min(C a,C b) {
return a<b?a:b;
}
int main()
{
string a="first string";
string b="second string";
cout<<"minimum string is: "<<min(a,b)<<'n';
int c=3,d=5;
cout<<"minimum number is: "<<min(c,d)<<'n';
double e{3.3},f{6.6};
cout<<"minimum number is: "<<min(e,f)<<'n';
char g{'a'},h{'b'};
cout<<"minimum number is: "<<min(g,h)<<'n';
return 0;
}
Ошибки:
13 [Error] call of overloaded 'min(std::string&, std::string&)' is ambiguous
6 [Note] C min(C, C) [with C = std::basic_string<char>]
Пожалуйста, помогите мне.
11
Решение
Здесь происходит две вещи.
Ваша первая проблема заключается в том, что вы включили только часть сообщения об ошибке. Вот ссылка на код, выполняемый в gcc и clang, и одно из полученных сообщений об ошибке (полностью):
main.cpp:13:34: error: call to 'min' is ambiguous
cout<<"minimum string is: "<<min(a,b)<<'n';
^~~
/usr/include/c++/v1/algorithm:2579:1: note: candidate function [with _Tp = std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >]
min(const _Tp& __a, const _Tp& __b)
^
main.cpp:6:3: note: candidate function [with C = std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >]
C min(C a,C b) {
^
Есть два кандидата. Один в main.cpp:6:3
(строка 6, символ 3) и один на algorithm:2579:1
(строка 2579, символ 1).
Один из них ты написал, а один из них в #include <algorithm>
,
Один из ваших заголовочных файлов включен <algorithm>
без тебя об этом. Стандартные заголовки могут делать это, как бы это ни раздражало.
В <algorithm>
Eсть std::min
шаблон функции. Как std::string
это экземпляр класса шаблона в namespace std
, шаблон функции std::min
обнаруживается с помощью процесса, называемого «поиск с учетом аргументов» или «поиск по Кенигу». (Кандидаты перегрузки функции ищутся локально, а также в пространствах имен аргументов функции, а также в пространствах имен аргументов шаблона для аргументов функции и в пространствах имен вещей, на которые указывают аргументы объекта. функция и т. д.)
Ваша местная функция min
также находится в том же пространстве имен, что и тело main
,
Оба одинаково хороши, и компилятор не может решить, какой из них вы хотите вызвать. Так что выдает ошибку, сообщающую вам об этом.
И gcc и clang делают error:
затем последовательность note:
s. Обычно все из note:
s после ошибки важны для понимания ошибки.
Чтобы это исправить, попробуйте позвонить ::min
(полностью квалифицируя вызов), или переименовав функцию во что-то другое, или сделайте вашу версию более подходящей, чем std::min
(сложно, но выполнимо в некоторых случаях), или вызов (min)(a,b)
, Последний блокирует поиск ADL / Koenig, а также блокирует раскрытие макроса (например, если какая-то ОС вставила #define min
макросы в их системные заголовки) (через @ 0x499602D2).
14
Другие решения
Вы столкнулись с именным столкновением с std::min
, Скорее всего, он включен в один из других стандартных заголовков библиотеки, которые вы включили, либо <iostream>
или же <string>
моё предположение, вероятно, последнее. Быстрое решение состоит в том, чтобы переименовать вашу функцию. Например, переименовав его в mymin
работает отлично. демонстрация
5