【问题标题】:How does "using std::swap" enable ADL?“使用 std::swap”如何启用 ADL?
【发布时间】:2015-03-23 17:13:50
【问题描述】:

What is the copy-and-swap idiom 中显示了这个例子:

friend void swap(dumb_array& first, dumb_array& second) // nothrow
{
    // enable ADL (not necessary in our case, but good practice)
    using std::swap; 

    // by swapping the members of two classes,
    // the two classes are effectively swapped
    swap(first.mSize, second.mSize); 
    swap(first.mArray, second.mArray);
}

using std::swap 究竟是如何启用 ADL 的? ADL 只需要一个非限定名称。我看到 using std::swap 的唯一好处是,由于 std::swap 是一个函数模板,您可以在调用中使用模板参数列表 (swap<int, int>(..))。

如果不是这样,那么using std::swap 是干什么用的?

【问题讨论】:

标签: c++ c++11 argument-dependent-lookup


【解决方案1】:

只是想补充一下为什么要使用这个成语,这似乎是原始问题的精神。

这个习语用在许多实现交换的标准库类中。来自http://www.cplusplus.com/reference/algorithm/swap/

标准库的许多组件(在 std 中)在一个 允许非基本类型的自定义重载的非限定方式 被调用而不是这个通用版本:交换的自定义重载 在与提供它们的类型相同的命名空间中声明 通过对这个泛型的依赖于参数的查找来选择 版本。

因此,使用不合格的“交换”来交换您描述的函数中的成员变量的目的是使 ADL 可以为这些类找到自定义的交换函数(如果它们存在于其他地方)。

由于这些自定义类不存在于您引用的类中(在原始示例中,mSize 和 mArray 分别是 std::size_t 和 int*),并且 std::swap 工作得很好,作者添加了一条评论,在这种情况下这不是必需的,而是良好的做法。如果他明确调用 std::swap,他会得到相同的结果,正如前面的答案中所指出的那样。

为什么这是好的做法?因为如果你有定义了自定义交换的类的成员实例,你希望行为是这样的:检查自定义交换函数......如果它存在,使用它,如果它不存在,使用标准库职能。在没有可用的自定义交换函数的情况下,您希望它默认为上面链接中描述的简单 std::swap 实现。因此,“使用”将内置类型的交换带入命名空间。但这些将在最后尝试。

另见:https://stackoverflow.com/a/2684544/2012659

如果出于某种原因您讨厌“使用 std::swap”,我想您理论上可以通过显式调用 std::swap 来手动解决此问题,以使用 std::swap 并使用您知道已定义的每个自定义交换的不合格交换(仍然使用 ADL 找到)。但这很容易出错……如果您没有编写这些类,您可能不知道是否存在自定义交换。在 std::swap 和 swap 之间切换会导致代码混乱。最好让编译器处理所有这些。

【讨论】:

    【解决方案2】:

    “启用 ADL”注释适用于转换

    std::swap(first.mSize, second.mSize);
    std::swap(first.mArray, second.mArray);
    

    using std::swap;
    swap(first.mSize, second.mSize);
    swap(first.mArray, second.mArray);
    

    你说得对,ADL 只需要一个非限定名称,但这就是代码被重新设计以使用非限定名称的方式。

    简单的

    swap(first.mSize, second.mSize);
    swap(first.mArray, second.mArray);
    

    不起作用,因为对于许多类型,ADL 找不到 std::swap,并且范围内没有其他可用的 swap 实现。

    【讨论】:

    • 你的意思是using std::swap 是没有关联命名空间或类的类型的后备?
    • @templateboy 是的,还有那些有关联命名空间但没有提供自定义 swap 函数的类型。最常见的类型都是内置类型。
    猜你喜欢
    • 2015-02-25
    • 2012-02-28
    • 1970-01-01
    • 1970-01-01
    • 2021-10-01
    • 2012-12-22
    • 2015-09-30
    相关资源
    最近更新 更多