I noticed strange behavior regarding function lookup when 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 expected the use of foo
inside bar
to find the overload below it. Moving the overload of foo
to above bar
makes the output the desired int:0
(or just writing a declaration).
This same behavior does not appear to apply to overloading a binary operator:
#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, the first is: Why is the behavior like this and why is it different for operator overloading? The second is: If I have a named function (like my use of foo
), is there a way to write a function bar
in such a way to discover overloaded foo
s declared later in a translation unit?
Welcome to the world of the most famous two phase lookup, and weirdo rules.
I'm sure there is no difference on operator and function cases just for the second you used one more argument. Try what happens if for the first version you also add another parameter with struct Foo...
Two phased lookup means that for dependent names when the template is compiled, it looks around and remember the set of visible functions. In your case that finds nothing. Then in the instantiation context there is another lookup, following the ADL (argument-dependent lookup) rules. That only. It means first collecting "associated namespaces" of the arguments, then look for more candidates in those namespaces.
In your case the only argument is int, and it has no associated namespaces, so nothing is found again. In the second case you also have Foo that drags :: with it, and your operator is found in ::.
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