gpt4 book ai didi

c++ - C++11 是否改变了显式调用 std::swap 以确保找到位于 ADL 的交换的行为,例如 boost::swap?

转载 作者:IT老高 更新时间:2023-10-28 12:53:46 31 4
gpt4 key购买 nike

背景

考虑以下代码:

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

现在 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
}

问题

std::swap 是否具有 C++11 中 boost::swap 的行为?如果不是,为什么?

在我看来,这似乎很明显。任何被更改破坏的代码一开始都可能非常脆弱(算法和容器,如 std::sortstd::vector,未指定;允许实现是否不确定地调用 ADL 交换),因此更改会更好。此外,现在为数组定义了 std::swap,因此完全改变当然不是不可能的。

然而,虽然 §17.6.3.2 规定在标准库中对 swap 的所有调用都必须在没有 std:: 限定的情况下完成(解决算法和容器的问题如上所述),它无法触及 std::swap 本身。它甚至给出了交换值的例子,包括 using std::swap;。同样,第 20.2.2 节(其中指定了 std::swap)在 ADL 上也只字未提。

最后,GCC 没有在他们的 std::swap 实现中启用 ADL(MSVC 也没有,但这没什么好说的)。所以我一定是错误的 std::swap 具有 boost::swap 的行为,但我不明白为什么没有进行更改。 :( And I'm not alone !

最佳答案

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

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; 并不足以抵消将上述代码静默转换为无限递归的缺点。

另一种摆脱使用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
}

关于c++ - C++11 是否改变了显式调用 std::swap 以确保找到位于 ADL 的交换的行为,例如 boost::swap?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9170247/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com