【问题标题】:what does `using std::swap` inside the body of a class method implementation mean?在类方法实现的主体中使用 std::swap 是什么意思?
【发布时间】:2011-06-14 12:55:37
【问题描述】:

在对这个问题进行了彻底的解释之后,我试图学习和采用复制交换习语:the Copy-Swap Idiom

但我发现了一些我从未见过的代码:using std::swap; // allow ADL 在这个例子中

class dumb_array
{
public:
    // ...

    void swap(dumb_array& pOther) // nothrow
    {
        using std::swap; // allow ADL    /* <===== THE LINE I DONT UNDERSTAND */

        swap(mSize, pOther.mSize); // with the internal members swapped,
        swap(mArray, pOther.mArray); // *this and pOther are effectively swapped
    }
};
  1. using std::swap; 在函数实现的主体内部是什么意思?
  2. ADL 是什么意思?

【问题讨论】:

  • MSalter's answer 恕我直言,显然是更好更全面的答案,因为他解释了 ADL(这是在此处执行 using 的全部原因)。我认为您应该选择它作为解决方案。

标签: c++ stl std using argument-dependent-lookup


【解决方案1】:

通过添加using std::swap,它可以在该功能中实现更广泛的灵活性。 swap 没有特定类型的版本,因为它是一个模板,因此为任何内置类型调用 std 版本都不会产生问题。

假设类 Foo 有一个成员 h 持有类型 ExampleType,我们为 ExampleType 定义了一个特定于类型的交换版本:

void swap(Foo& lhs, Foo& rhs)
{
    //ERROR: This would only the call std version 
    std::swap(lhs.h, rhs.h);
}

上面的例子只会调用 std 版本而不是我们的 ExampleType 版本。所以通过包含using std::swap,程序将调用我们定义的版本而不是std::swap

void swap(Foo& lhs, Foo& rhs)
{
    using std::swap;
    std::swap(lhs.h, rhs.h);   //Using class defined version of swap()
}

即使我们用内置函数替换了被交换的参数,代码仍然可以正常执行,因为编译器会推断 std 版本是最佳选择。此概念也称为参数相关查找或 ADL。

【讨论】:

    【解决方案2】:

    这种机制通常用于模板代码,即template &lt;typename Value&gt; class Foo

    现在的问题是使用哪个交换。 std::swap&lt;Value&gt; 可以,但可能并不理想。对于Value 类型,很有可能有更好的swap 重载,但是在哪个命名空间中呢?几乎可以肯定它不在std:: 中(因为这是非法的),但很可能在Value 的命名空间中。有可能,但还不确定。

    在这种情况下,swap(myValue, anotherValue) 将为您提供可能的“最佳”交换。 Argument Dependent Lookup 将在 Value 来自的命名空间中找到任何交换。否则using 指令启动,std::swap&lt;Value&gt; 将被实例化并使用。

    在您的代码中,mSize 可能是一个整数类型,而mArray 可能是一个指针。两者都没有关联的命名空间,而且std::swap 无论如何都具有 99.9% 的确定性对它们来说是最佳的。因此,using std::swap; 声明在这里似乎毫无用处。

    【讨论】:

    • 我相信在 std 命名空间内提供标准模板化函数的特化是非常合法的。 §17.4.3.1/1 “程序可以将任何标准库模板的模板特化添加到命名空间std。标准库模板的这种特化(完整或部分)会导致未定义的行为,除非声明依赖于用户定义的名称外部链接,除非特化满足原始模板的标准库要求”也就是说,在 std 命名空间中实现 swap 特化并不常见。
    • @dribeas:确实,专门化std::swap 是合法的,如果对您的用户有疑问,您可能应该专门化std::swap 在您的ADL 可以找到自己的命名空间。但是特化std::swap 是有限制的,杀手是你不能部分特化它,因为它是一个函数模板,所以如果你写了一个类模板(比如一个新的容器),你不能专门化std::swap,因此你必须走ADL路线。不过,MSalters 的说法是正确的:你不能超载 std::swap,只能专攻。
    【解决方案3】:

    using 关键字具有作用域。

    这意味着std::swapusing 关键字的范围内可以被称为swap

    【讨论】:

    • 我相信 ADL 在这种情况下只是意味着“依赖于参数的查找”。这允许代码在定义或不定义本地交换函数的情况下使用“交换”。如果本地不存在,则使用 std::swap
    • @vmpstr:如果你把它作为一个单独的答案,你会因为我投票而获得 10 声望。
    • 老实说,这是一个无用的答案。它没有解释using std::swap 和ADL 的交互。 MSalters 的答案应该是被接受的。
    • @Maxim Yegorushkin:答案可能不完整,但如果提问者不知道using 关键字,那么答案并非毫无用处。仅供参考,我赞成 MSalters 的回答,因为它比我的更深入。
    • @Maxim,我的问题主要是关于 using 关键字,然后只问 ADL 是什么。我很高兴@Benoit 和 @MSalters 分别回答了 1. 和 2.。
    猜你喜欢
    • 2016-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-30
    • 2019-06-02
    • 1970-01-01
    • 1970-01-01
    • 2016-10-17
    相关资源
    最近更新 更多