重载解析在模板函数中的工作方式不同吗?

Is overload resolution working differently inside template function?

考虑这段代码。

在进一步阅读之前尝试猜测程序的输出:

#include <iostream>
using namespace std;

template <typename T>
void adl(T) {
    cout << "T";
}

struct S {
};

template <typename T>
void call_adl(T t) {
    adl(S());
    adl(t);
}

void adl(S) {
    cout << "S";
}

int main() {
    call_adl(S());
}

你完成了吗?好的。

所以这个程序的输出是TS,这看起来违反直觉(至少对我来说)。

为什么 call_adl 中的调用 adl(S()) 使用模板重载而不是使用 S 的模板重载?

name lookup 模板中依赖名称和非依赖名称的行为不同。

For a non-dependent name used in a template definition, unqualified name lookup takes place when the template definition is examined. The binding to the declarations made at that point is not affected by declarations visible at the point of instantiation. For a dependent name used in a template definition, the lookup is postponed until the template arguments are known, at which time ADL examines function declarations with external linkage (until C++11) that are visible from the template definition context as well as in the template instantiation context, while non-ADL lookup only examines function declarations with external linkage (until C++11) that are visible from the template definition context (in other words, adding a new function declaration after template definition does not make it visible except via ADL).

也就是说对于adl(S());,在call_adl之后声明的adl(S)是不可见的,那么选择模板化的adl(T)。对于 adl(t);t 是一个从属名称(取决于模板参数 T),查找被推迟并且 adl(S) 被 ADL 找到并且它胜过 adl(T) 在重载决议中。