稍后定义的重载函数的名称查找

时间:2013-07-02 18:48:53

标签: c++ name-lookup

当依赖于稍后定义的函数时,我注意到关于函数查找的奇怪行为:

#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在翻译单位?

1 个答案:

答案 0 :(得分:2)

欢迎来到最着名的两阶段查找和怪人规则的世界。

我确信运算符和函数情况没有区别,只是因为你再使用了一个参数。尝试如果对于第一个版本,您还使用struct Foo ...

添加另一个参数会发生什么

两个分阶段查找意味着对于编译模板时的从属名称,它会环顾四周并记住可见函数集。在你的情况下什么也没发现。然后在实例化上下文中,遵循ADL(依赖于参数的查找)规则进行另一次查找。只有。这意味着首先收集参数的“关联命名空间”,然后在这些命名空间中查找更多候选项。

在您的情况下,唯一的参数是int,并且它没有关联的命名空间,因此不会再找到任何内容。在第二种情况下,你也有Foo用它拖动::你的运算符在::。