非预先声明的函数调用适用于类类型,但不适用于基本类型

Cur*_*ous 13 c++ argument-dependent-lookup c++17

在以下代码中

template <typename T>
void foo(T) {
    bar(T{});
}

class Something {};
void bar(Something) {}

int main() {
    foo(Something{});
}
Run Code Online (Sandbox Code Playgroud)

(https://wandbox.org/permlink/l2hxdZofLjZUoH4q)

当我们foo()使用Something参数调用时,一切都按预期工作,调用将调度到bar(Something)重载.

但是当我将参数更改为整数并提供bar(int)重载时,我得到一个错误

template <typename T>
void foo(T) {
    bar(T{});
}

void bar(int) {}

int main() {
    foo(int{});
}
Run Code Online (Sandbox Code Playgroud)

错误:

error: call to function 'bar' that is neither visible in the template definition nor found by argument-dependent lookup
Run Code Online (Sandbox Code Playgroud)

(https://wandbox.org/permlink/GI6wGlJYxGO4svEI)

在类的情况下,我没有bar()在命名空间中定义以及Something.这意味着我没有得到ADL.那么为什么代码适用于类类型呢?

Jod*_*cus 7

那么为什么代码适用于类类型呢?

根据§6.4.2/ 2.1:

命名空间和类的集合按以下方式确定:

  • 如果T是基本类型,则其关联的命名空间和类集都是空的.

因此,在编写时foo(int),编译器将具有一组空的名称空间和类以供考虑.因此,呼吁bar必须失败,因为它尚未宣布.如果您foo(int)事先声明,您的代码将编译:

void bar(int);

template <typename T>
void foo(T) {
    bar(T{});
}

void bar(int) {}

int main() {
    foo(int{});
}
Run Code Online (Sandbox Code Playgroud)

另一方面,在这种情况下foo(Something),(全局)命名空间将成为查找的一部分,因此编译器会主动扫描命名空间以查找bar可以使用Something实例调用的命名函数.