<utility> 执行 swap() 时不一定包含 - 这怎么会成为问题?

<utility> not necessarily included when swap() is performed - How can this become a problem?

正在阅读C++ named requirements: Swappable我遇到了以下注释

It is unspecified whether <utility> is actually included when the standard library functions perform the swap, so the user-provided swap() should not expect it to be included.

假设我有一个 user-defined 类型 class Foo 和一个 user-provided swap()。我想为我的 class Foo 使用标准库算法,该算法与

执行交换
using std::swap;
swap(arg1, arg2);

如 above-mentioned cppreference 文章中所述,以及我必须 #include 使用此算法不会 #include <utility>

如果我在 swap() 中依赖 <utility> 提供的功能,这怎么会导致问题?我必须在定义我的 swap() 的文件中 #include <utility> 自己。该场景应类似于以下内容:我有一个文件,其中 #includes 我的 class Foo 和我的 user-provided swap() 以及我使用的算法的 header .因此,关于算法是否 #include <utility> 永远不会有问题。

我可能对 #include 和编译在某些不同情况下如何相互作用有误解。哪种情况可能会导致编译问题?

简短的回答是,如果没有明确的 #include <utility>,如果 Foo 没有自定义 swap,则无法保证 std::swap 回退;导致编译错误。

如果代码中某处有 using std::swap; 语句 - 您的代码或算法内部 - 则必须已经包含 std::swap 函数,否则会出现编译错误。

cppreference 指出的是,无法保证 std::foo_algorithm 将包含 <utility> 并在调用 swap(a,b) 之前使用 using std::swap; 构造。请注意,它使用不合格的名称进行交换。

这意味着如果您的 class 依赖于 std::swap 的存在,因为它缺少任何自定义 swap 函数,那么调用 std::foo_algorithm 可能会导致编译错误说由于 std::swap 未被自动包含,因此没有合适的 swap(Foo&,Foo&) 函数。简单的解决方法是将 #include <utility> 放在 #include <foo_algorithm>.

之前

但是,如果您有一个自定义交换并且算法可以找到它(因为它要么直接包含在当前命名空间中,要么因为 ADL 启动),一切都可以正常编译。与此无关,无论如何,您的交换应该使用 using std::swap; swap(a,b); 构造,因此如果您的 swap 存在,则 std::swap 可能始终存在。

让我们试着理解你从 cppreference 引用的注释。

It is unspecified whether <utility> is actually included when the standard library functions perform the swap, so the user-provided swap() should not expect it to be included.

例如,std::sort 可以执行交换。要使用 std::sort,您需要包含 <algorithm>。该声明基本上说,尽管如此,<algorithm> 可能没有包含 <utility>。因此下面的代码可能有问题。

#include <algorithm>

int main() {
  int arr[] = { 4, 1, 7 };
  std::sort(arr, arr + 3);
  std::swap(arr[0], arr[1]); // may error out here
}

这是违反直觉的,因为 std::sort 在内部执行 std::swap为了安全起见,如果需要 std::swap,请始终明确包含 <utility>。不要假设其他一些使用 std::swap 的标准库头文件本身包含了 <utility> 以下代码应该始终有效,而 #include <utility> 乍一看似乎没有必要.

#include <algorithm>
#include <utility>

int main() {
  int arr[] = { 4, 1, 7 };
  std::sort(arr, arr + 3);
  std::swap(arr[0], arr[1]);
}