Finding Names for Overloaded Functions Defined Later

I noticed strange behavior regarding function search, relying on a function to be defined later:

#include <iostream> template <typename T> void foo(const T&) { std::cout << "Basic" << std::endl; } template <typename T> void bar() { T x; foo(x); } void foo(const int& x) { std::cout << "int:" << x << std::endl; } int main() { bar<int>(); } 

Output:

 Basic 

For some reason, I was expecting foo be used inside bar to find the overload below it. Moving the foo overload above bar makes the output int:0 (or just writing the declaration) desired.

The same behavior does not seem to apply to binary operator overloading:

 #include <iostream> struct Foo {} foo; template <typename T> void operator<<(const Foo&, const T&) { std::cout << "Basic" << std::endl; } template <typename T> void bar() { T x; foo << x; } void operator<<(const Foo&, const int& x) { std::cout << "int:" << x << std::endl; } int main() { bar<int>(); } 

Output:

 int:0 

I have two questions: first, why is this behavior and why is it different from operator overloading? Second: if I have a named function (e.g. using foo ), is there a way to write the bar function in such a way as to detect an overloaded foo , declared later in the translation block?

+4
source share
1 answer

Welcome to the world of weirdo's most famous two-step searches and rules.

I am sure that there is no difference in operational and functional cases, because for the second you used one more argument. Try what happens if for the first version you add another parameter with the Foo structure ...

Two phased searches mean that for dependent names, when compiling a template, it scans and remembers a set of visible functions. In your case, it does not find anything. Then, in the instance context, there is another search, following ADL rules (depending on the argument). Just this. This means first collecting “related namespaces” of the arguments, and then looking for more candidates in these namespaces.

In your case, the only argument is int, and it has no associated namespaces, so nothing was found again. In the second case, you also have Foo that drags :: with it, and your statement is in ::.

+2
source

Source: https://habr.com/ru/post/1489343/


All Articles