C ++ 11改变了显式调用std :: swap的行为,以确保找到ADL定位的交换,如boost :: swap? [英] Does C++11 change the behavior of explicitly calling std::swap to ensure ADL-located swap's are found, like boost::swap?

查看:740
本文介绍了C ++ 11改变了显式调用std :: swap的行为,以确保找到ADL定位的交换,如boost :: swap?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下代码:

#include <utility>

namespace ns
{
    struct foo
    {
        foo() : i(0) {}
        int i;

    private:
        foo(const foo&); // not defined,
        foo& operator=(const foo&); // non-copyable
    };

    void swap(foo& lhs, foo& rhs)
    {
        std::swap(lhs.i, rhs.i);
    }
}

template <typename T>
void do_swap(T& lhs, T& rhs); // implementation to be determined

int main()
{
    ns::foo a, b;
    do_swap(a, b);
}

在C ++ 03中, do_swap 将被视为已损坏:

In C++03, this implementation of do_swap would be considered "broken":

template <typename T>
void do_swap(T& lhs, T& rhs)
{
    std::swap(lhs, rhs);
}

通过明确指定 std :: ,它禁止通过参数相关查找找到 ns :: swap 。 (它然后无法编译,因为 std :: swap 尝试复制 foo ,这是不允许的)。 ,我们这样做:

By explicitly specifying std::, it prohibits ns::swap from being found via argument-dependent lookup. (It then fails to compile because std::swap tries to copy a foo, which is not allowed.) Instead, we do this:

template <typename T>
void do_swap(T& lhs, T& rhs)
{
    using std::swap; // allow std::swap as a backup if ADL fails to find a swap
    swap(lhs, rhs); // unqualified call to swap, allow ADL to operate
}

现在 ns :: swap ,并且不使用 std :: swap ,不太专用。它是丑陋的,但它的工作,是可以理解的后视。 boost :: swap 为我们很好地包装(并提供数组重载):

Now ns::swap is found and std::swap, being less specialized, is not used. It's uglier, but it works and is understandable in hind-sight. boost::swap wraps this up nicely for us (and provides array overloads):

#include <boost/swap.hpp>

template <typename T>
void do_swap(T& lhs, T& rhs)
{
    boost::swap(lhs, rhs); // internally does what do_swap did above
}



问题



我的问题是 std :: swap 执行 boost :: swap 在C ++ 11?如果没有,为什么?

Question

My question is thus: does std::swap take on the behavior of boost::swap in C++11? If not, why?

对我来说,似乎很明显,它应该。任何被更改破坏的代码可能是相当脆弱的(算法和容器,如 std :: sort std :: vector ,被低估了;实现被允许调用ADL swap的或不是不确定的),所以改变会更好。此外, std :: swap 现在定义为数组,所以更改肯定不是问题。

To me it seems obvious that it ought to. Any code broken by the change was probably quite flimsy in the first place (algorithms and containers, like std::sort and std::vector, were underspecified; implementations were allowed to call ADL swap's or not indeterminately), so the change would be for the better. Additionally, std::swap is now defined for arrays, so change at all certainly isn't out of the question.

但是,虽然§17.6.3.2规定在标准库中对 swap 的所有调用都必须在 std :: qualification(修正上面提到的算法和容器的问题),它不能触及 std :: swap 本身。它甚至给出了包含使用std :: swap; 的交换值的示例。同样,§20.2.2(指定 std :: swap )不会在ADL上说一个字。

However, while §17.6.3.2 specifies that all calls to swap within the standard library must be done without std:: qualification (fixing the problem with algorithms and containers noted above), it fails to touch on std::swap itself. It even gives examples of swapping values that include using std::swap;. Likewise §20.2.2 (where std::swap is specified) doesn't say a word on ADL.

最后,GCC不在其 std :: swap 实现中启用ADL(MSVC也不行,但这不是很多)。所以我一定错误, std :: swap 采取的行为 boost :: swap ,但我不'了解为什么没有改变。 (我不孤单

Lastly, GCC does not enable ADL in their std::swap implementation (nor does MSVC, but that's not saying much). So I must be wrong that std::swap takes on the behavior of boost::swap, but I don't understand why the change wasn't made. :( And I'm not alone!

推荐答案

如果提议的话,我将不得不投票反对你的概念验证实现,恐怕会破坏下面的代码,我相信我在野外看到的在过去十几年内至少一次或两次。

I would have had to vote against your proof-of-concept implementation had it been proposed. I fear it would break the following code, which I'm pretty sure I've seen in the wild at least once or twice over the past dozen years.

namespace oops
{

    struct foo
    {
        foo() : i(0) {}
        int i;

        void swap(foo& x) {std::swap(*this, x);}
    };

    void swap(foo& lhs, foo& rhs)
    {
        lhs.swap(rhs);
    }

}

无论你认为上面是好的代码还是坏的,它的工作原理是作者打算在C ++ 98/03,所以,默认打破它的酒吧是相当高。告诉用户,在C + + 11,他们不再需要写使用std :: swap; 不是一个足够高的好处,超过默默地将上述代码转换为无限递归的缺点。

Whether you think the above is good code or bad, it works as the author intends in C++98/03 and so the bar for silently breaking it is pretty high. Telling users that in C++11 they would no longer have to write using std::swap; isn't a sufficiently high benefit to outweigh the disadvantage of silently turning the above code into infinite recursion.

另一种出路使用std :: swap; 使用 std :: iter_swap 代替: b

Another way to get out of writing using std::swap; is to use std::iter_swap instead:

template <typename T>
void do_swap(T& lhs, T& rhs)
{
    std::iter_swap(&lhs, &rhs); // internally does what do_swap did above
}

这篇关于C ++ 11改变了显式调用std :: swap的行为,以确保找到ADL定位的交换,如boost :: swap?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆