一般的なスワップ関数の実装として以下の例をあげている。
namespace std
{
template<typename T>
void swap(T& a, T&anp; b)
{
T temp(a);
a = b;
b = temp;
}
}
この形のスワップ関数を効率良くするためには、クラスを実装の為のクラスと、実装を指すメンバ変数のみの本体の二つに分ける。
class WidgetImpl
{
private:
int a, b, c;
std::vector<double> v;
}
class Widget
{
private:
WidgetImpl *pImpl;
}
これにより、ポインタ一つの入れ換えになるので、動作が軽くなる。
特殊化の技法を基にして、Widget クラスの swap を作ることが出来る。
class Widget
{
public:
void swap(Widget& other)
{
using std::swap;
swap(pImpl, other.pImpl);
}
}
namespace std
{
template<>
void swap<Widget>(Widget& a, Widget& b)
{
a.swap(b);
}
}
メンバ関数のスワップ関数を作り、非メンバ関数から呼び出す。
std 名前空間は特殊で新しいテンプレート、クラス、関数などを入れる事は出来ない。その為、このクラスがクラステンプレートであった場合はこの様な特殊化は出来ない。そこで、swap 関数を std 名前空間に入れることはしないが、クラステンプレートと同じ名前空間内に非メンバ関数を用意する。 書式は以下の様になる。
namespace WidgetStuff
{
template<typename T>
class Widget
{
void swap(Widget<T>& other);
};
template<typename T>
void swap(Widget<T>& a, Widget<T&t;& b)
{
a.swap(b);
}
}
クラステンプレートでは、実行時に一番適した関数が呼ばれる様に手助けをする必要がある。
template<typename T>
void doSomething(T& obj1, T& obj2)
{
using std::swap;
swap(obj1, obj2);
}
C++ の機構により、obj1 と obj2 に適した型の関数が探される。もし、特殊化された swap 関数があれば、それが呼ばれる。 もし、特殊化 swap 関数が無い時には std から呼ばれるように using std::swap
を入れる。std::swap
の形で呼ぶと、特殊化 swap 関数が呼ばれなくなってしまう。
セコメントをする