この場合、クラステンプレートの特殊化はやり過ぎです。機能の約90%が同一になる場合でも、クラス全体を異なるタイプに複製する必要があります。
重要なのは、異なる部分を分離し、それらだけを専門化することです。ただし、いくつかの理由から、特殊化よりもオーバーロードを使用する方が簡単です。
あなたの場合の異なる部分は、配列項目への値の割り当てだけです。
template <typename T>
class Array {
void add(T elem) {
if(size == capacity) expandArr();
assignItem(elem);
size++;
}
template <typename U>
void assignItem(U elem) {
arr[size] = elem;
}
void assignItem(char* elem) {
// Incidentally, DON’T DO THIS! It leaks. Use RAII!
arr[size] = new char[strlen(elem) + 1];
strcpy(arr[size], word);
}
};
もちろん、これで、サポートされているタイプのハードコーディングがArray
完了しました。コピーコンストラクターを持つタイプのみが char*
サポートされ、他のタイプはサポートされていません。一般に、この制限は必要ありません。任意のタイプをサポートし、コピー方法を指定できるようにする必要があります1。
これを達成する方法はいくつかあります。ここでは、型のコピー方法を指定するトレイトクラスを介して1つを説明します。
template <typename T>
struct CopyConstruct {
void assign(T& target, T source) const {
target = source;
}
};
template <typename T, typename Copy = CopyConstruct<T>>
class Array {
Copy copier;
void add(T elem) {
if(size == capacity) expandArr();
copier.assign(arr[size], elem);
size++;
}
};
このクラスは、最初のクラスと同じように使用できます。の場合char*
、ユーザーには2つの選択肢があります。特殊化するかCopyConstruct
、インスタンス化するときに完全に独自の特性を提供するかのいずれかですArray
。
struct CopyCString {
void assign(char*& target, char* source) const {
target = new char[strlen(elem) + 1];
strcpy(arr[size], word);
}
};
// And then:
Array<char*, CopyCString> strArray;
(ここではポインタへの参照を渡していることに注意してください。そうしないと、ポインタをアイテム自体ではなく配列アイテムのコピーに割り当てるため、割り当てられたメモリが失われます。)
1しかし実際には、C++はまさにその目的のためにコピーコンストラクターをすでに使用しています。実際の解決策char*
は上記のいずれでもありません。のようなコピー可能なタイプにラップすることstd::string
です。