为什么编译器发现我的函数尚未声明

Why does the compiler find my function if is not yet declared?

本文关键字:未声明 函数 我的 编译器 发现 为什么      更新时间:2023-10-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::funcn"; } }
namespace b { void do_func(item) { std::cout << "b::funcn"; } }
输出:

a::func
b::func

使用在线编译器验证:

  • gcc 4.8
  • 叮当声3.4

如果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的组合才能使其工作。

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

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

看看这个:

  • 可怕的两阶段名称查找

简而言之,do_func是一个依赖的名称,所以在第一阶段(当文件只有解析,但函数模板没有实例化时),编译器不解析名称do_func,它只有检查语法,它看到这是一个有效的函数调用。就这些。在第二个阶段,当函数模板被实例化时(因此T是已知的),名称do_func被解析,此时它也使用ADL来查找该名称。

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