像 operator<< 、 operator* 这样的成员函数需要 ADL 才能工作吗?

Does member function like operator<< , operator* need ADL to work?

我有一个代码片段(假设):

#include <iostream>

struct Pirate {
 void song_name() {
  std::cout << "Bink's Sake\n";
 }

 Pirate& operator*(Pirate const& other) {
  // do something
  return *this;
 }
};

int main() {
 Pirate p1{} p2{};
 p1.song_name(); // does this use qualified or unqualifed name lookup?
 
 p1 * p2;

 std::cout << 5;
 std::cout << 'a';
}

p1 * p2 是使用限定名称查找还是非限定名称查找或 ADL?

std::cout << 5 转换为 std::cout.operator<<(5); std::cout << 'a' 转换为 std::operator<<(std::cout, 'a');

成员函数是否需要 ADL 才能工作? 以上两个语句是否使用限定或非限定名称查找或 ADL?

谢谢

运算符查找non-static成员函数如

std::cout.operator<<(5);

但如果它们有 non-member 变体,non-member 也可以通过非限定查找和 ADL 运行。所有这些一起构成了重载集。

为了使其正常工作,non-member 变体应该通过 ADL 找到,即放置在 class 的名称空间内,它们正在为其重载运算符。例如。要为您自己的 class 重载 operator<<,您不能使用成员版本,因为第一个参数可能应该是从 std::ostream 派生的任何内容。那么 non-member 变体上的 ADL 是让它在任何地方都能工作的唯一方法。

如果名称所属的范围使用 scope-resolution 运算符 ( ::) 或 成员访问运算符 .->)。

案例一

因此,当您写道:

p1.song_name(); //here p1.song_name is a qualified name

在上面的语句中,p1.song_name 是一个 限定名称,所以这里发生 限定查找

案例二

接下来,当您写道:

p1 * p2;

以上语句等同于:

p1.operator*(p2);

因为你的 class Pirate 有一个重载的成员函数 operator*,上面的语句将使用那个成员函数。上面的语句也使用了 qualified lookup 因为我们使用了 member access operator ..

案例三

这里有语句:

std::cout << 5;

以上语句等同于:

std::cout.operator<<(5);

使用 限定查找 因为它有成员访问运算符 .

案例 4

这里我们看声明:

operator<<(std::cout, 'a');

此处使用了 ofstreamoperator<<char 重载。这使用 ADL 因为在这种情况下第一个参数具有 class 类型。因此,编译器还将查找定义了 cout 的命名空间。因此,对于此调用,编译器还会查找 std 命名空间并找到 char 重载。