- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
考虑以下代码:
#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::sort
和 std::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/
我是一名优秀的程序员,十分优秀!