如何在C++中为List<char>模板类特化string参数构造函数?
为List添加专属string构造函数的C++实现
需求:练习C模板时,希望仅为List<char>类添加接受C string的构造函数,其他类型(如List<double>)不需要该构造函数。
用户原代码
#include <iostream> #include <string> #include <cstring> using namespace std; template <typename T> class CollectionInterface { public: virtual T get(); virtual void set(int index, T value); virtual void add(T value); virtual int length(); }; template <typename T> class ListItem { public: T value; ListItem* next; ListItem* prev; }; template <typename T> class List: public CollectionInterface<T> { public: List(){} List(T* arr, int length){ init(arr,length); } ~List(){ } protected: void init(T* arr, int length){ } ListItem<T>* first; ListItem<T>* last; }; template<char> class List<char> { public: List<char>(string s){ char char_array[s.length() + 1]; strcpy(char_array, s.c_str()); this->init(char_array,s.length()); } }; int main() { List<char> list("Hello World!"); //cout << "Hello World!" << endl; return 0; }
编译错误
Line 40: Partial specialization of 'List' does not use any of its template parameters
Line 45: No member named 'init' in 'List'
错误原因
- 特化语法错误:
template<char> class List<char>是错误写法,针对T=char的全特化应使用template<>,因为这里没有额外模板参数需要指定,直接特化整个List模板即可。 - 全特化类未继承原模板成员:全特化后的
List<char>是独立类,不会自动继承原模板List<T>的init函数、first/last成员,因此调用this->init会提示找不到该成员。
两种解决方案
方案一:SFINAE限制模板构造函数(推荐,无需全特化类)
在原List<T>模板中添加仅当T=char时生效的构造函数,无需修改类整体结构:
#include <iostream> #include <string> #include <type_traits> using namespace std; template <typename T> class CollectionInterface { public: virtual T get() = 0; virtual void set(int index, T value) = 0; virtual void add(T value) = 0; virtual int length() = 0; }; template <typename T> class ListItem { public: T value; ListItem* next; ListItem* prev; ListItem(T val) : value(val), next(nullptr), prev(nullptr) {} }; template <typename T> class List: public CollectionInterface<T> { public: List() : first(nullptr), last(nullptr), size(0) {} List(T* arr, int length) : first(nullptr), last(nullptr), size(0) { init(arr, length); } // 仅T为char时启用的string构造函数 template<typename U = T, typename = enable_if_t<is_same_v<U, char>>> List(const string& s) : first(nullptr), last(nullptr), size(0) { for (char c : s) { add(c); } } ~List() { ListItem<T>* curr = first; while (curr) { ListItem<T>* next = curr->next; delete curr; curr = next; } } T get() override { return first ? first->value : T(); } void set(int index, T value) override { ListItem<T>* curr = first; for (int i = 0; i < index && curr; ++i) { curr = curr->next; } if (curr) curr->value = value; } void add(T value) override { ListItem<T>* newItem = new ListItem<T>(value); if (!first) { first = last = newItem; } else { last->next = newItem; newItem->prev = last; last = newItem; } size++; } int length() override { return size; } protected: void init(T* arr, int length) { for (int i = 0; i < length; ++i) { add(arr[i]); } } ListItem<T>* first; ListItem<T>* last; int size; }; int main() { List<char> list("Hello World!"); cout << "List length: " << list.length() << endl; return 0; }
说明:
- 用
std::enable_if_t和std::is_same_v(C17及以上,C11可改用std::is_same<U, char>::value)限制构造函数仅在T=char时生效。 - 修复基类纯虚函数问题,原代码基类虚函数无实现,派生类必须实现才能实例化。
- 添加析构函数释放链表内存,避免内存泄漏。
方案二:正确全特化List类
若坚持使用全特化,需让特化类继承基类并重新实现所有必要成员:
#include <iostream> #include <string> using namespace std; template <typename T> class CollectionInterface { public: virtual T get() = 0; virtual void set(int index, T value) = 0; virtual void add(T value) = 0; virtual int length() = 0; }; template <typename T> class ListItem { public: T value; ListItem* next; ListItem* prev; ListItem(T val) : value(val), next(nullptr), prev(nullptr) {} }; template <typename T> class List: public CollectionInterface<T> { public: List() : first(nullptr), last(nullptr), size(0) {} List(T* arr, int length) : first(nullptr), last(nullptr), size(0) { init(arr, length); } ~List() { ListItem<T>* curr = first; while (curr) { ListItem<T>* next = curr->next; delete curr; curr = next; } } T get() override { return first ? first->value : T(); } void set(int index, T value) override { ListItem<T>* curr = first; for (int i = 0; i < index && curr; ++i) { curr = curr->next; } if (curr) curr->value = value; } void add(T value) override { ListItem<T>* newItem = new ListItem<T>(value); if (!first) { first = last = newItem; } else { last->next = newItem; newItem->prev = last; last = newItem; } size++; } int length() override { return size; } protected: void init(T* arr, int length) { for (int i = 0; i < length; ++i) { add(arr[i]); } } ListItem<T>* first; ListItem<T>* last; int size; }; // 正确的全特化语法 template<> class List<char> : public CollectionInterface<char> { public: List() : first(nullptr), last(nullptr), size(0) {} List(char* arr, int length) : first(nullptr), last(nullptr), size(0) { init(arr, length); } // 专属string构造函数 List(const string& s) : first(nullptr), last(nullptr), size(0) { for (char c : s) { add(c); } } ~List() override { ListItem<char>* curr = first; while (curr) { ListItem<char>* next = curr->next; delete curr; curr = next; } } char get() override { return first ? first->value : '\0'; } void set(int index, char value) override { ListItem<char>* curr = first; for (int i = 0; i < index && curr; ++i) { curr = curr->next; } if (curr) curr->value = value; } void add(char value) override { ListItem<char>* newItem = new ListItem<char>(value); if (!first) { first = last = newItem; } else { last->next = newItem; newItem->prev = last; last = newItem; } size++; } int length() override { return size; } protected: void init(char* arr, int length) { for (int i = 0; i < length; ++i) { add(arr[i]); } } ListItem<char>* first; ListItem<char>* last; int size; }; int main() { List<char> list("Hello World!"); cout << "List length: " << list.length() << endl; return 0; }
说明:
- 使用
template<> class List<char>的正确全特化语法,替换原错误写法。 - 特化类重新实现基类所有纯虚函数,以及
init、add等必要成员,保证功能完整。 - 替换原代码中非标准的变长数组,改用遍历string的方式添加字符,提升代码可移植性。
内容的提问来源于stack exchange,提问作者kess
相关产品推荐
相关产品推荐

