首页 > 解决方案 > 重载解析在模板函数中的工作方式是否不同?

问题描述

考虑这段代码。

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

#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,这看起来违反直觉(至少对我来说)。

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

标签: c++templatesoverloading

解决方案


对于模板中的依赖名称和非依赖名称,名称查找的行为是不同的。

对于模板定义中使用的非依赖名称,在检查模板定义时会进行非限定名称查找。在该点对声明的绑定不受实例化点可见的声明的影响。对于模板定义中使用的依赖名称,查找被推迟到模板参数已知,此时 ADL 检查with external linkage (until C++11)从模板定义上下文以及模板实例化上下文中可见的函数声明,而非 ADL 查找仅检查with external linkage (until C++11)从模板定义上下文可见的函数声明(换句话说,在模板定义之后添加新函数声明不会使其可见,除非通过 ADL)。

这意味着 for adl(S());adl(S)声明后call_adl不可见,然后adl(T)选择模板。对于adl(t);,t是一个依赖名称(取决于模板参数T),查找被推迟并由 ADL 找到,并在重载决议中adl(S)胜出。adl(T)


推荐阅读