【发布时间】:2012-02-28 12:37:48
【问题描述】:
背景
请考虑以下代码:
#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!
【问题讨论】:
-
我还记得一直听说C++11的
std::swap应该使用ADL,奇怪。 -
如果要交换的项目在命名空间中,这里有什么依赖于 koenig 查找规则吗?当然,您始终可以为任何特定类型重载 swap,因为 swap 是一个模板,因此您的重载将始终优先于通用模板,例如 void swap(MyT&a, MyT&b) { a.swap(b); }
-
@CashCow:您的意思是专注于
std命名空间?这在某些时候有效(不能部分专门化函数,所以没有模板类),但它很笨拙并且不利于良好的设计。 -
Howard Hinnant 下面的回答给出了一个很好的反例。但是,请注意 Eric Niebler(至少)已经提议
std::swap(或类似的东西)应该按照你想要的方式行事。请参阅 "Customization Point Design in C++11 and Beyond"(2014 年 10 月的博文)和 N4381 Suggested Design for Customization Points,它们于 2015 年 5 月在 Lenexa 上进行了讨论。
标签: c++ c++11 swap language-lawyer rationale