Are function objects treated differently from regular functions during overload resolution? If so, how?
I have run into the following case where replacing a function with an equivalently-callable function object changed the meaning of the code:
#include <iostream>
namespace N
{
enum E { A, B };
void bar(E mode) { std::cout << "N::bar\n"; }
}
template <typename... Args>
void bar(Args&&... args) { std::cout << "global bar\n"; }
int main()
{
bar(N::A);
}
Here the output is "N::bar". So far, so good: N::bar is being found by ADL, both N::bar and the global bar are exact matches, and N::bar is preferred because it's not a template.
But if I change the global bar to be a function object, like so:
#include <iostream>
namespace N
{
enum E { A, B };
void bar(E mode) { std::cout << "N::bar\n"; }
}
struct S
{
template <typename... Args>
void operator()(Args&&... args) { std::cout << "global bar\n"; }
};
S bar;
int main()
{
bar(N::A);
}
The output is now "global bar". Why the difference?
Using the function overloading concept, we can develop more than one function with the same name, but the arguments passed should be of different types. Function overloading executes the program faster. Function overloading is used for code reusability and to save memory.
Function overloading shows the behavior of polymorphism that allows us to get different behavior, although there will be some link using the same name of the function. Function overloading speeds up the execution of the program. Function overloading is used for code reusability and also to save memory.
The process of selecting the most appropriate overloaded function or operator is called overload resolution. Suppose that f is an overloaded function name. When you call the overloaded function f() , the compiler creates a set of candidate functions.
To overload functions, they must have a different= set of parameters, i.e., either have parameters of different data types or a different number of parameters in the function definition. Functions with different return types and identical parameters can not be overloaded.
The important bit here is that ADL only kicks in if lookup determines that the name is a function in the function call. In the second case, bar
is found to be an object and not a function, so the expression bar(N::A)
is not a function call, but the application of operator()
to the object bar
. Because it is not a function call, ADL does not kick in and N::bar
is not considered.
3.4.1/3
The lookup for an unqualified name used as the postfix-expression of a function call is described in 3.4.2. [ Note: For purposes of determining (during parsing) whether an expression is a postfix-expression for a func- tion call, the usual name lookup rules apply. The rules in 3.4.2 [ADL] have no effect on the syntactic interpretation of an expression.
Another way to look at it is to notice that ADL will add new functions to the set of overloaded functions, but in the second example there is no such set: lookup finds an object and a member of the object is called.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With