1

我最初打算为 Array 样式的类使用模板,然后将其传递 achar*或 an 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++;
    }
}

还有另一种合法检查元素类型的方法吗?或者我应该把这两个班级分开并让他们独立吗?

我最初尝试使用模板类,因为这两种 Array 类型具有相同的功能,但是在这种情况下,对于char*'s 和int's 的内存分配方式存在一些根本差异。

4

2 回答 2

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 回答
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

有几种方法可以实现这一点。我将在这里通过一个指定如何复制类型的特征类来说明一个。

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*,用户有两种选择:要么 specialize CopyConstruct,要么在实例化时提供完全自己的 trait 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 回答