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?
问题描述
请考虑以下代码:
#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屋!