如果尚未声明,为什么编译器会找到我的函数?

Sta*_*ked 16 c++ overload-resolution

与我的期望相反,这个程序有效:

#include <iostream>


namespace a { struct item{}; }
namespace b { struct item{}; }


template<typename T>
void func(T t) { do_func(t); }


int main()
{    
    func(a::item{});
    func(b::item{});
}


namespace a { void do_func(item) { std::cout << "a::func\n"; } }
namespace b { void do_func(item) { std::cout << "b::func\n"; } }
Run Code Online (Sandbox Code Playgroud)

输出:

a::func
b::func
Run Code Online (Sandbox Code Playgroud)

在线编译器验证:

如果瞬间func<T>发生在身体main然后我会期待a::do_func并且b::do_func尚未宣布.

这怎么办?

更新

根据@Marc Claesen的说法,上述原因是:

在读取所有源之后执行模板实例化

但是,那么为什么这个代码并不能正常工作:

#include <iostream>

template<typename T>
void func(T t) { do_func(t); }

int main()
{
    func(1);
}

void do_func(int) { std::cout << "do_func(int)\n"; }
Run Code Online (Sandbox Code Playgroud)

gcc-4.8:

error: 'do_func' was not declared in this scope,
and no declarations were found by argument-dependent
lookup at the point of instantiation [-fpermissive]
Run Code Online (Sandbox Code Playgroud)

clang ++ 3.4:

error: call to function 'do_func' that is neither
visible in the template definition nor found by
argument-dependent lookup
Run Code Online (Sandbox Code Playgroud)

因此,似乎需要功能模板和ADL的组合才能使其工作.

但是,我不明白为什么会这样.

Naw*_*waz 14

它的作用是因为有两个有趣的事情:

  • 执行两阶段名称查找以查找从属名称.
  • 和参数依赖查找(ADL).

看看这个:

总之,do_func是一个从属名称,所以在第一阶段(当文件被唯一的解析,但该函数模板没有实例化)编译器并没有解析名称do_func,它只是检查语法和它认为它是一个有效的函数调用.就这些.在功能模板实例化(因此T已知)的第二阶段,do_func解析名称,此时它还使用ADL查找名称.

请注意,ADL仅适用于用户定义的类型.它不适用于内置类型,这就是你的第二个代码(即func(1))不起作用的原因!