c++:模板的类型萃取
2017-11-19 20:07
543 查看
首先,需要举一个例子来说明c++在什么情况下需要对不同的类型不同对待。
这是一个模板类的顺序表,实现了尾插和增容两个接口。
接下来进行测试:
它是没有问题的:
但是如果里面存string类型:
可以看到,它崩溃了,而且打印出来了数据,说明是在析构的时候崩溃,到底怎么回事?
如图,因为使用得是memcpy,所以新开辟的空间的前三个_str和_a指向的空间的每一个_str指向的一样。
这样就导致delete[] _a的时候,新开辟的空间的前三个_str为野指针,必然崩溃。
如果需要解决问题,只要这样做:
利用operator=,通过for循环依次赋值,这样新旧_str指向的空间不同,解决了问题。
现在就出现了需要对不同的类型不同对待的情况,因为memcpy的效率比for循环高得多,但是对特殊类型又不得不使用for循环。
使用全特化可以解决:
这不是一个好办法,这样做会让代码的复用性很差,全是重复代码。
现在就该类型萃取出场了:
想要读懂这段代码不容易,我总结一下:
通过TypeCopy,那么就可以根据类型来确定拷贝方案。
template <class T> class SeqList { public: SeqList() :_a(NULL) , _size(0) , _capacity(0) {} void CheckCapacity() { if (_size >= _capacity) { _capacity = _capacity > 0 ? _capacity * 2 : 3;//当容量为0时增容为3,之后每次增2倍 T* newA = new T[_capacity]; if (_a != NULL) { memcpy(newA, _a, _size*sizeof(T));//使用memcpy } delete[] _a; _a = newA; } } void PushBack(const T& x) { CheckCapacity(); _a[_size++] = x; } void Print() { for (size_t i = 0; i < _size; i++) { cout << _a[i] << " "; } cout << endl; } private: T* _a; size_t _size; size_t _capacity; };
这是一个模板类的顺序表,实现了尾插和增容两个接口。
接下来进行测试:
void TestSeqList() { SeqList<int> s1; s1.PushBack(1); s1.PushBack(2); s1.PushBack(3); s1.PushBack(4); s1.Print(); }
它是没有问题的:
但是如果里面存string类型:
可以看到,它崩溃了,而且打印出来了数据,说明是在析构的时候崩溃,到底怎么回事?
如图,因为使用得是memcpy,所以新开辟的空间的前三个_str和_a指向的空间的每一个_str指向的一样。
这样就导致delete[] _a的时候,新开辟的空间的前三个_str为野指针,必然崩溃。
如果需要解决问题,只要这样做:
for (size_t i = 0; i < _size; i++) { newA[i] = _a[i]; }
利用operator=,通过for循环依次赋值,这样新旧_str指向的空间不同,解决了问题。
现在就出现了需要对不同的类型不同对待的情况,因为memcpy的效率比for循环高得多,但是对特殊类型又不得不使用for循环。
使用全特化可以解决:
template <> class SeqList<int> { public: SeqList() :_a(NULL) , _size(0) , _capacity(0) {} void CheckCapacity() { if (_size >= _capacity) { _capacity = _capacity > 0 ? _capacity * 2 : 3; int* newA = new int[_capacity]; if (_a) { memcpy(newA, _a, _size*sizeof(int)); } delete[] _a; _a = newA; } } void PushBack(const int& x) { CheckCapacity(); _a[_size++] = x; } ~SeqList() { delete[] _a; _size = _capacity = 0; } private: int* _a; size_t _size; size_t _capacity; };
template <> class SeqList<string> { public: SeqList() :_a(NULL) , _size(0) , _capacity(0) {} void CheckCapacity() { if (_size >= _capacity) { _capacity = _capacity > 0 ? _capacity * 2 : 3; string* newA = new string[_capacity]; if (_a) { for (size_t i = 0; i < _size; i++) { newA[i] = _a[i]; } delete[] _a; } _a = newA; } } void PushBack(const string& x) { CheckCapacity(); _a[_size++] = x; } ~SeqList() { delete[] _a; _size = _capacity = 0; } private: string* _a; size_t _size; size_t _capacity; };
这不是一个好办法,这样做会让代码的复用性很差,全是重复代码。
现在就该类型萃取出场了:
struct __TrueType//一个空类 {}; struct __FalseType//空类 {}; template <class T> struct __TypeTraits { typedef __FalseType ISPODType; //默认为不是基本类型 POD(基本类型) }; template <> struct __TypeTraits<int> { typedef __TrueType ISPODType; //int是基本类型 }; template <class T> T* TypeCopy(T* dst, const T* src, size_t n) { return __TypeCopy(dst, src, n, __TypeTraits<T>::ISPODType()); } template <class T> T* __TypeCopy(T* dst, const T* src, size_t n,__TrueType) { cout << "memcpy()" << endl; return (T*)memcpy(dst, src, n*sizeof(T)); } template <class T> T* __TypeCopy(T* dst, const T* src, size_t n, __FalseType) { for (size_t i = 0; i < n; i++) { dst[i] = src[i]; } cout << "operator=()" << endl; return dst; }
想要读懂这段代码不容易,我总结一下:
通过TypeCopy,那么就可以根据类型来确定拷贝方案。
相关文章推荐
- C++ 模板 之 类型萃取 与 容器适配器
- C++ 模板类型萃取技术 traits
- C++ 模板 之 类型萃取 与 容器适配器
- c++:模板的类型萃取
- 【C++】模板简述(五):类型萃取
- C++ 模板类型萃取技术 第一部分 为什么要有萃取技术
- 小结 | C++模板的类型萃取
- C++ 模板类型萃取技术 第二部分 基于泛型的类型萃取技术
- c++ 类型萃取(模板类型 运用)
- C++ 模板类型萃取技术
- C++语法基础--模板实参推断,模板类型形参的实参的受限转换,模板实参推断与函数指针
- C++的类型萃取技术
- C++类型萃取
- Effective C++第七章-模板和泛型编程之需要类型转换时请为模板定义非成员函数
- C++箴言:用成员函数模板接受兼容类型
- Effective Modern C++翻译(2)-条款1:明白模板类型推导
- C++ 模板判断类型
- 模板的类型萃取
- C++之运用成员模板接受所有兼容类型(45)---《Effective C++》
- C++模板类的类型萃取技术