当依赖于稍后定义的函数时,我注意到关于函数查找的奇怪行为:
#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>();
}
输出:
Basic
出于某种原因,我希望在foo
内使用bar
来查找它下方的重载。将foo
的重载移到bar
以上会使输出成为所需的int:0
(或只是写一个声明)。
这种相同的行为似乎不适用于重载二元运算符:
#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>();
}
输出:
int:0
我有两个问题,第一个是:为什么这样的行为以及为什么它与运算符重载不同?第二个是:如果我有一个命名函数(比如我使用foo
),有没有办法以这样的方式编写函数bar
来发现稍后声明的重载foo
在翻译单位?
答案 0 :(得分:2)
欢迎来到最着名的两阶段查找和怪人规则的世界。
我确信运算符和函数情况没有区别,只是因为你再使用了一个参数。尝试如果对于第一个版本,您还使用struct Foo ...
添加另一个参数会发生什么两个分阶段查找意味着对于编译模板时的从属名称,它会环顾四周并记住可见函数集。在你的情况下什么也没发现。然后在实例化上下文中,遵循ADL(依赖于参数的查找)规则进行另一次查找。只有。这意味着首先收集参数的“关联命名空间”,然后在这些命名空间中查找更多候选项。
在您的情况下,唯一的参数是int,并且它没有关联的命名空间,因此不会再找到任何内容。在第二种情况下,你也有Foo用它拖动::你的运算符在::。