与我的期望相反,这个计划有效:
#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"; } }
输出:
a::func
b::func
使用在线编译器进行验证:
如果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"; }
请参阅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]
error: call to function 'do_func' that is neither
visible in the template definition nor found by
argument-dependent lookup
因此,似乎需要功能模板和ADL的组合才能使其工作。
但是,我不明白为什么会这样......
答案 0 :(得分:14)
它起作用是因为有两个有趣的事情:
看看这个:
简而言之,do_func
是一个从属名称,因此在第一阶段(当文件仅解析但函数模板未实例化时)编译器不解析名称do_func
,仅检查语法,它看到它是一个有效的函数调用。就这些。在实例化函数模板的第二阶段(因此T
已知),名称do_func
已解析,此时它还使用ADL查找名称。
请注意,ADL仅适用于用户定义的类型。它不适用于内置类型,这就是你的第二个代码(即func(1)
)不起作用的原因!