バックグラウンド
この質問については、次のコードを検討してください。
#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::
禁止します。(許可されていないa をコピーしようと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
}
Nowns::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
次のとおり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 は実装で ADL を有効にしませんstd::swap
(MSVC も有効にしませんが、それはあまり意味がありません)。std::swap
したがって、の動作を引き継ぐのは間違っているに違いありませboost::swap
んが、変更が行われなかった理由がわかりません。:(そして私は一人じゃない!