为什么编译器找到我的功能,所以如果尚未宣布?(Why does the compiler find

2019-09-15 03:56发布

出乎我的意料,这个程序的工作原理:

#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

验证在线编译器:

  • GCC 4.8
  • 铛3.4

如果的instantation func<T>在体内发生main然后我会期望a::do_funcb::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的组合是必需的,使其工作。

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

Answer 1:

它的工作原理是因为两个有趣的事情:

  • 其中执行查找相关的名字两阶段名称查找
  • 与争议相关的查找(ADL)。

看看这个:

  • 可怕的两阶段名称查找

总之, do_func是一个从属名称,所以在第一阶段(当文件解析,但函数模板不是实例)编译器解析名称do_func ,它检查语法和它认为它是一个有效函数调用。 就这些。 在第二阶段中,当函数模板实例(并且因此T是已知的),名称do_func得到解决,此时它也使用ADL查找名称。

需要注意的是ADL仅适用于用户定义类型。 它不适用于内建类型的工作,这就是为什么你的第二个代码(即func(1)不工作!



文章来源: Why does the compiler find my function if is not yet declared?