不同的功能取决于模板类中的类型

时间:2013-02-06 23:23:17

标签: c++ templates types

我原本打算将模板用于Array风格的类,只需将它传递给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++;
    }
}

还有另一种合法检查元素类型的方法吗?或者我应该将这两个类分开并使它们独立?

我最初尝试使用模板化类,因为两种数组类型具有相同的功能,但在这种情况下,char*int'的内存分配方式存在一些根本区别。秒。

2 个答案:

答案 0 :(得分:2)

您应该使用template specialisation为不同的模板类型设置不同的行为。

将您的代码更改为:

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++;
    }
}

答案 1 :(得分: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*,用户有两种选择:要么专门化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