C++11 是否会更改显式调用 std::swap 的行为以确保找到位于 ADL 的交换区(如 boost::swap)?

2024-05-02

背景

考虑以下代码:

#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将被视为“损坏”:

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

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

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
}

Now ns::swap被发现并且std::swap,由于不太专业,不被使用。它比较丑陋,但它有效并且事后看来是可以理解的。boost::swap为我们很好地包装了它(并提供了数组重载):

#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
}

Question

Does std::swap采取的行为boost::swap在 C++11 中?如果没有,为什么?

对我来说,显然应该这样做。任何因更改而损坏的代码一开始都可能非常脆弱(算法和容器,例如std::sort and std::vector,未指定;实现被允许调用 ADL 交换(或者不是不确定的),所以这个改变会更好。此外,std::swap现在是为数组定义的,所以完全改变当然不是不可能的。

然而,虽然 §17.6.3.2 指定所有调用swap在标准库内必须完成std::资格(解决上面提到的算法和容器的问题),它没有触及std::swap本身。它甚至给出了交换值的示例,包括using std::swap;。同样§20.2.2(其中std::swap已指定)没有提及 ADL。

最后,GCC 并未在其系统中启用 ADLstd::swap实现(MSVC 也没有,但这并没有说明太多)。所以我一定是错的std::swap采取的行为boost::swap,但我不明白为什么没有做出改变。 :(我并不孤单 https://stackoverflow.com/a/6115281/87234!


如果您提出概念验证实施方案,我将不得不投票反对。我担心它会破坏下面的代码,我很确定在过去的十几年里我在野外至少见过一两次。

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 中他们不再需要编写using std::swap;并没有足够高的好处来抵消默默地将上述代码变成无限递归的缺点。

另一种摆脱写作的方法using std::swap;是使用std::iter_swap反而:

template <typename T>
void do_swap(T& lhs, T& rhs)
{
    std::iter_swap(&lhs, &rhs); // internally does what do_swap did above
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++11 是否会更改显式调用 std::swap 的行为以确保找到位于 ADL 的交换区(如 boost::swap)? 的相关文章

随机推荐