1

私はもともと配列スタイルのクラスのテンプレートを使用して、それをchar*またはに渡すつもりでしたintが、次のようなものを実装しようとすると問題が発生しました。

template<Typename T>
class Array {
    void add(T elem) {
        if(size == capacity) expandArr();
        if(T == char*) //g++ threw errors here
            arr[size] = new char[strlen(word) + 1];
            strcpy(arr[size], word);
        else if(T == int) {
            arr[size] = elem;
        }

        size++;
    }
}

要素タイプを合法的にチェックする別の方法はありますか?または、2つのクラスを分離して、それらを独立させる必要がありますか?

両方の配列型が同じ機能を持っているため、私はもともとテンプレートクラスを使用しようとしていましたが、この場合のメモリの割り当て方法にはいくつかの基本的な違いがありchar*ますint

4

2 に答える 2

2

この場合、クラステンプレートの特殊化はやり過ぎです。機能の約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です。

于 2013-02-07T09:29:33.537 に答える
2

テンプレートの種類ごとに異なる動作をするには、テンプレートの特殊化を使用する必要があります。

コードを次のように変更します。

template<typename T>
class Array {
    void add(T elem) {
        if(size == capacity) expandArr();

        size++;
    }
}

template<>
class Array<char*> {
    void add(T elem) {
        if(size == capacity) expandArr();
        arr[size] = new char[strlen(word) + 1];
        strcpy(arr[size], word);

        size++;
    }
}

template<>
class Array<int> {
    void add(T elem) {
        if(size == capacity) expandArr();
        arr[size] = elem;

        size++;
    }
}
于 2013-02-07T00:11:06.623 に答える