I am a beginner in C++. I wanted to know, how internally the function overloading takes place in C++
I recommend you reading C++ Primer. This concept is explained in depth.
On a higher level, function overloading is allowed if both the functions
have same name
declared in the same scope
have different parameter list.
On the lower-level ( inside how compiler figures it out), here's how it is done.
There are 3 steps for function overloading resolution.
e.g void f();
void f(int);
void f(double, double = 3.4);
void f(char *, char *);
Function call inside main -> void f(5.6);
Identifies the set of overloaded functions considered for the call, they are called as candidate functions. A candidate function is a function with the same name as the function that is called & for which declaration is visible at the point of call.
It also identifies the properties of the argument list in the function call, i.e no of arguments and their types.
Selected : All 4 functions with name 'f'
Selects the function from the set of candidate functions found in step 1 that can be called with arguments specified in the call. Those are called as viable functions.
A viable function is a function that has the same nof of parameters or more parameters ( addn paramters has an associated default argument) than the arguments in the actual function call. Types of arguments must be convertible for the function to be classified as viable.
Selected : void f(int) and void (double, double =3.4)
Identifies the best viable function among the all viable functions.
For (int) conversion need to apply which is a standard conversion (double to int). But for (double, double=3.4), there's a exact match, so no conversion needed. No conversion is better than a conversion.
Selected : void (double, double = 3.4 )
It takes place internally with mangled names.
For the file
void blah(int f)
{
}
void blah(double f)
{}
I get the symbols
ethan#EthanPc ~ % nm blah.o
0000000000000009 T _Z4blahd
0000000000000000 T _Z4blahi
Notice the d for double, and the i for integer.
Related
How can I receive in a function definition when the one of the parameter in function call is void?
The scenario is that one of my projects, in a function call one of the parameters is void. That section I could not change.
I can change only the function declaration or the function definition, but I still confused what I need to change.
Please help
Below code is not a executable one:
for ex:
#include <stdio.h>
void test(void, int a) {
printf("%d", a);
}
int main() {
test(void, 32);
}
You can't. That is not valid C:
<source>:2:11: error: 'void' must be the only parameter
2 | void test(void,int a)
| ^~~~
Same goes for C++:
<source>:2:11: error: invalid use of type 'void' in parameter declaration
2 | void test(void,int a)
| ^~~~
The only valid use of void as parameter is on it's own, as in:
int bar();
int foo(void);
In C this means the function bar takes an undetermined number of arguments while foo does not take any arguments. In C++ both are equivalent.
void is an incomplete type and cannot be used as the parameter of a function(in both C and C++) with the exception that if void is the only parameter of that function. This can be seen from the following quoted statements.
C++
From function's documentation:
Parameter list determines the arguments that can be specified when the function is called. It is a comma-separated list of parameter declarations, each of which has the following syntax:
5 Indicates that the function takes no parameters, it is the exact synonym for an empty parameter list: int f(void); and int f(); declare the same function. Note that the type void (possibly cv-qualified) cannot be used in a parameter list otherwise: int f(void, int); and int f(const void); are errors (although derived types, such as void* can be used). In a template, only non-dependent void type can be used (a function taking a single parameter of type T does not become a no-parameter function if instantiated with T = void).
Note also that there is a semantic difference(between C++ & C) in case void is used as a parameter of a function and is the only parameter as shown in the following example:
int func(void); //declaration of func that takes no parameter and has the return type of void
int foo(); //declaration of foo that takes no parameter and has the return type of void
C
From function declaration's documentation:
parameters cannot have type void (but can have type pointer to void). The special parameter list that consists entirely of the keyword void is used to declare functions that take no parameters.
int f(void); // OK
int g(void x); // Error
Unlike in C++ and function definitions (since C23), the declarators f() and f(void) have different meaning: the declarator f(void) is a new-style (prototype) declarator that declares a function that takes no parameters. The declarator f() is a declarator that declares a function that takes unspecified number of parameters (unless used in a function definition)
Please refer to the following:
struct functorOverloaded
{
void operator()(const int& in_, ...) const {}
void operator()(short in_) {}
};
// helper to resolve pointer to overloaded function
template <typename C, typename... OverloadArgs>
auto resolve_overload(
std::invoke_result_t<C, OverloadArgs...> (C::* func)(OverloadArgs..., ...) const
)
{ return func; };
int main(int argc, char **argv)
{
using C = const functorOverloaded;
// works with exact function type
using myT = decltype(resolve_overload<C, const int&>(&C::operator()));
// can call with something convertible to const int&
static_assert(std::is_invocable_v<C,int>, "!!!");
// how to get the pointer to the overload that would be called when passed int (or double)?
// the next line doesn't compile (error C2672: 'resolve_overload': no matching overloaded function found)
using myT2 = decltype(resolve_overload<C, int>(&C::operator()));
return 0;
}
The above code allows retrieving a pointer to a specific overload of a function (operator() in this case), see here. One must know the exact argument type (const int&) in this case to get the pointer, even though i can just call the specific overload with a plain int, or even double. Is it possible to get a pointer to the overload that would be called with the specific argument (assuming the call is resolvable / not ambiguous)?
Edit: adding context:
I am writing a invocable_traits library for introspecting a callable. E.g., given a Callable, it will tell you the return type, arity and argument types, amongst some other properties. To support functors (including lambdas) with overloaded (or templated) operator(), the API of invocable_traits allows specifying call arguments to disambiguate which overload is to be used (or to instantiate the template). However, one must know the exact argument type (const int& in the example above), simply specifying int won't do in that case as there is no function with signature R operator()(int). Ideally, I'd like to allow discovering the signature of the exact overload/instantiation that gets called given the provided input argument types, ideally even taking into account any implicit conversions that are applied. Is this possible?
There is no way to get the function of an overload-set which would be called with the given arguments, unless you already know its signature.
And if you know, what's the point?
The problem is that for any given arguments, taking into account implicit conversions, references, cv-qualifiers, noexcept, old-style vararg, default arguments, and maybe also literal 0 being a null pointer constant, there are an infinite number of function-signatures which would match. And there is currently no facility for "just" listing all candidates.
I know that you can declare a function without any arguments simply like this:
void test()
{
cout << "Hello world!!" << endl;
}
But I have also seen
void test(void)
{
cout << "Hello world!!" << endl;
}
and
void test(void*)
{
cout << "Hello world!!" << endl;
}
My question is: What is the difference between using void and void* here?
The one an only form for a function with no parameters in C++ should be
void test();
The form:
void test(void)
That is how you define a function with no parameters in c. But in C++ use this form only for interfacing with c:
extern "C"
{
void test(void);
}
This form:
void test(void*)
Is not a function with no arguments. It has an argument of type void* that is unnamed. It expects a void* pointer when called.
Have a look here for an explanation of what a void* pointer is: What does void* mean and how to use it?
What is the difference between using void and void* here?
When the argument type is void, the function must be called without any arguments.
When the argument type is void*, the function must be called with an argument that is a void* or can be converted to a void*.
void stands for "nothing" but void* does not stand for "pointer to nothing". In fact, it's quite the contrary. void* stands for pointer to anything except void. It is oxymoronic but that's how the language defines those two.
My question is: What is the difference between using void and void* here?
(void) parameter list is same as empty parameter list. The void here does nothing in C++ and is unnecessary unless compatibility with C is needed - see the second part of the answer.
(void*) does not accept 0 arguments. It accepts 1 argument. The type of the parameter is void* which is a pointer type.
Why is it like this?
Because of backwards compatibility with C. In C, (void) is the only way to declare a function that only accepts empty argument list. () parameter list declares any function without specifying the parameters. The number of parameters could be any, including 0. The use of () parameter list in C is becoming an obsolete feature.
Quote from C11 standard draft N1548:
Function declarators (including prototypes)
An identifier list declares only the identifiers of the parameters of the function. An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. The empty list in a function declarator that is not part of a definition of that function specifies that no information about the number or types of the parameters is supplied.
Future language directions
Function declarators
The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature.
Function definitions
The use of function definitions with separate parameter identifier and declaration lists (not prototype-format parameter type and identifier declarators) is an obsolescent feature.
C is this way because of backward compatibility with older versions (pre-standard) of C where parameter lists weren't declared.
In C++ these two declarations of a function
void test();
and
void test(void);
are equivalent and mean that the function does not take any arguments.
In C, the first function declaration declares a function with an empty identifier list, and the second function declaration declares a function with a parameter type list that in fact has no parameters.
According to the C Standard (6.9.1 Function definitions):
5 If the declarator includes a parameter type list, the declaration of
each parameter shall include an identifier, except for the special
case of a parameter list consisting of a single parameter of type
void, in which case there shall not be an identifier. No declaration
list shall follow.
This declaration of the function (that is also its definition)
void test(void*)
{
//...
}
has 1 parameter, an object of type void * (pay attention to that pointers are always complete types), that is not used within the function.
This declaration is valid in C++, and is not valid in C, because in C each function parameter in a function declaration with a parameter type list that is at the same time its definition shall have an identifier, except in the case when a void parameter is used, as specified in the quote above.
In C you may use such a declaration only when the declaration is not at the same type its definition.
So in C for example you may write like
void test(void*); // declaratipon
and then
void test( void *ptr ) // declaration and definition
{
//...
}
I need some help understanding how overloaded C++ functions are selected by the compiler.
When given a function:
type func(type1 x, type2 y);
type func(type3 x, type2 y);
How does the compiler determine which function to choose?
I know the function chosen is according to its suitability, but how to you know which function is chosen if either could be used successfully.
For example:
Given these function overloaded functions:
char* average(int i, float f, double d);
double average(double d, float f, int i);
double fabs(double d);
Given these variables:
int i1, i2, i3;
float f1, f2, f3;
What data type is the return value of these function calls? and why?
average(i1, i2, i3);
average(f1, f2, f3);
fabs(average(f1,f2,f3));
The return value depends on the function call that is made. For example your first function call would return value double because second average function is called.
The function overloading solely takes place on basis of arguments irrespective of return types. You can't overload two functions solely on basis that they have different return types. The functions should differ by arguments in order for function overloading to work.
In order to compile a function call, the compiler must first perform name lookup, which, for functions, may involve argument-dependent lookup(ADL).
If these steps produce more than one candidate function, then overload resolution is performed to select the function that will actually be called.
In general, the candidate function whose parameters match the arguments most closely is the one that is called.
As in your case:
1--> char* average(int i, float f, double d);
2--> double average(double d, float f, int i);
Here in both of your functions you have completly different argument list. 1st average is taking int, float, double and the 2nd one is double, float, int.
So, compiler decides which method to invoke first based in its arguments.
If you invoke method with argument (int, float, double) the overloaded version takes 1st method and if you invoke method with argument (double, float, int) the overloaded version takes 2nd method.
The choice if which overloaded method to call(in other words, the signature of the method) is decided at compile time.
So, compiler will already know the signature of the method to be invoked.
While overloading methods we must keep the following rules in mind:
Overloaded methods MUST change the argument list,
Overloaded methods CAN change the return types.
Overloaded methods CAN change the access modifier.
A method can be overloaded in the same class or in a subclass.
Can i actually use a function overloading like this:
#include <iostream>
void foo(...)
{
std::cout << "::foo(...) \n";
}
void foo(int)
{
std::cout << "::foo(int) \n";
}
int main()
{
foo(0);
foo('A');
foo("str");
foo(0, 1);
}
What standard says about it? And in what kind of situations i'll get ::foo(...)?
void foo(int)
will accept one argument of type int.
void foo(...)
accepts any number of arguments, of any type. It will be selected when the call doesn't have a single int argument. Not very useful, in general.
Also note that it is undefined behavior to pass objects of class type to ....
In N3337 I can see:-
13.3.2 Viable functions
A candidate function having fewer than m parameters is viable only if
it has an ellipsis in its parameter list (8.3.5). For the purposes of
overload resolution, any argument for which there is no corresponding
parameter is considered to “match the ellipsis” (13.3.3.1.3) .
When you declare a function in the following way :
void foo (...)
this mean foo accepts any number of arguments.
So this function will be called when this is the must suitable one.
In your case whenever you won't write :
foo(//Some single int).
In your specific main, this will happen :
foo(0) //Calls foo(int).
foo('A) //Calls foo (int). as you can convert a char to an int.
foo("str") //Calls foo(...) . as you can not convert a string to an int.
foo(1,2) //Calls foo(...) . as this is the only possible function
cause the second foo function only takes one int.
void foo(...) will take variable arguments. And it will be called when there the no or type of argument does not match the provided argument list of other function with the same function name.
foo(0); //This will call void foo(int) function
foo('A'); //This will call void foo(int) function
foo("str"); //This will call void foo(...) function
foo(0, 1); //This will call void foo(...) function
NOTE:
Although the ellipsis works fine with function overloading, it is not highly recommend pursuing variadic functions. At least not until you have significantly more experience in C++ to understand the pitfalls. I would suggest its use only with the try catch block where there are situations when the error cannot be predicted.