ショートストーリー:できるだけオーバーロードして、必要なときに特化してください。
ロングストーリー:C++では、特殊化と過負荷の扱いが大きく異なります。これは一例で最もよく説明されています。
template <typename T> void foo(T);
template <typename T> void foo(T*); // overload of foo(T)
template <> void foo<int>(int*); // specialisation of foo(T*)
foo(new int); // calls foo<int>(int*);
ここで最後の2文字を入れ替えましょう。
template <typename T> void foo(T);
template <> void foo<int*>(int*); // specialisation of foo(T)
template <typename T> void foo(T*); // overload of foo(T)
foo(new int); // calls foo(T*) !!!
コンパイラーは、特殊化されていないものも見ています。したがって、どちらの場合も、オーバーロードの解像度はfoo(T*)
を選択します。ただし、int*
の特殊化はfoo(T)
の特殊化であり、foo(T*)
ではないため、最初のケースでのみfoo<int*>(int*)
が見つかります。
std::swap
と記載しました。これは物事をさらに複雑にします。
標準では、std
名前空間に特殊化を追加できます。あなたはFoo
のタイプを持っています。それにはパフォーマンススワップがあり、次にを指定すると、std
名前空間にswap(Foo&, Foo&)
があります。問題はありません。
Foo
がテンプレートクラスの場合はどうなりますか? C++には関数の部分的な特殊化がないため、swap
を特化することはできません。唯一の選択はオーバーロードですが、標準では、std
名前空間にオーバーロードを追加することはできません。
あなたはこの時点で2つのオプションがあります。
は、独自の名前空間にswap(Foo<T>&, Foo<T>&)
関数を作成し、それがADLを経由していますことを願っています。標準ライブラリがstd::swap(a, b);
のようなスワップを呼び出すと、単にADLが機能しなくなるので、私は "希望"と言います。
標準のオーバーロードを追加しないでくださいと言っている部分を無視してください。正直なところ、技術的には許可されていないにもかかわらず、現実的なシナリオではうまくいくはずです。
ただし、標準ライブラリがswap
を使用するという保証はありません。ほとんどのアルゴリズムはstd::iter_swap
を使用していますが、私が調べた実装によっては、必ずしもstd::swap
に転送されるとは限りません。
グレート例サー – tenfour
この点は指摘された...「ので、私は希望を言います」数年前にWG21に登場しました。すべての標準ライブラリ実装者は、そうでないことを知っています。 – MSalters
素敵な答え、ありがとうございました。 –