16

与我的预期相反,该程序有效:

#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]

铿锵++ 3.4

error: call to function 'do_func' that is neither
visible in the template definition nor found by
argument-dependent lookup

所以似乎需要函数模板和ADL的结合才能使其工作。

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

4

1 回答 1

14

它之所以有效,是因为有两个有趣的事情:

  • 两阶段名称查找,用于查找相关名称。
  • 和参数相关查找 (ADL)。

看看这个:

简而言之,do_func是一个依赖名称,因此在第一阶段(仅解析文件但未实例化函数模板时)编译器解析名称do_func它只检查语法并认为它是一个有效的函数调用. 就这些。在函数模板被实例化(因此T是已知的)的第二阶段,名称do_func被解析,此时它还使用 ADL 来查找名称。

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

于 2013-05-18T11:20:09.090 回答