【问题标题】:Is overload resolution working differently inside template function?重载解析在模板函数中的工作方式是否不同?
【发布时间】:2021-03-14 13:17:36
【问题描述】:

考虑这段代码。

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

#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 的那个?

【问题讨论】:

  • 请注意,如果将void adl(S) 的定义移到call_adl 之前,则输出为SS godbolt.org/z/v6KThs。也许这就是你所期望的。虽然我也无法详细解释原因。
  • 在尝试调用它之前,您至少需要声明adl(S)。否则它不参与重载,你会得到模板化的版本。

标签: c++ templates overloading


【解决方案1】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多