C++ 模板 之 类型萃取 与 容器适配器

类型萃取 在模板这里主要就是对于模板的不同类型的实例化 有不同的方案 这样可以提高效率等

比如 下面的 顺序表 在扩容时的拷贝

对于没有含有指向空间的指针的类 如int 自动使用memcpy()

对于含有指向空间的指针的类 如string 就自动一个一个的赋值 防止浅拷贝导致两个指针指向同一空间 析构两次时出错

类型萃取实现 主要用到了 模板  模板特化 内嵌型别  也可用函数重载 详见Copy()

//(1)-------类型萃取 实现顺序表

//----------------------Copy.h-------------------------

#ifndef __COPY_H__

#define __COPY_H__

#include<string>

#include<iostream>

using namespace std;

struct TrueType //内置类型

{

bool Get()

{

//cout<<"TrueType"<<endl;

return true;

}

};

struct FalseType //非内置类型

{

bool Get()

{

//cout<<"FalseType"<<endl;

return false;

}

};

template<class _Tp> //_Tp 类型 默认(没特化)使用 循环 一个一个赋值

struct TypeTraits

{

typedef FalseType isPodType; //内嵌型别

};

//==========================

// 特化:实现同一个类型isPodType对于不同的特化表示的类型不同 如 FalseType/TrueType

// 使用 memcpy 的类型 用struct TypeTraits<...>{typedef TrueType isPodType; };

template<>

struct TypeTraits<int>

{

typedef TrueType isPodType;

};

template<>

struct TypeTraits<char>

{

typedef TrueType isPodType;

};

template<>

struct TypeTraits<float>

{

typedef TrueType isPodType;

};

template<>

struct TypeTraits<double>

{

typedef TrueType isPodType;

};

//还有未特化的 这里只是举几个例子 实际中应尽可能写完整......

// 使用 循环 一个一个赋值的类型 使用struct TypeTraits<...>{typedef FalseType isPodType; };

template<>

struct TypeTraits<string>

{

typedef FalseType isPodType;

};

//==========================================

//============== 函数重载 的 应用 【Copy第一种方式的实现原理】==============

int m_copy(int a, int b, int)

{

return 0;

}

int m_copy(int a, int b, float)

{

return 0;

}

#if 0 //==========================

//============ 1 萃取  Copy的第1种方法 ==============

// 利用 函数重载来区分 FalseType  TrueType

template <typename T>

void Copy(T* dst, const T* src, int size, FalseType)

{

cout<<"__FalseType"<<typeid(T).name()<<endl;

for (int i = 0; i < size; ++i)

{

dst[i] = src[i];

}

}

template <typename T>

void Copy(T* dst, const T* src, int size, TrueType)

{

cout<<"__TrueType"<<typeid(T).name()<<endl;

memcpy(dst, src, size * sizeof(T));

}

void test2()

{

int arr1[] = {1,2,3,4,5,6,7,8,9};

int arr2[9];

int sz = sizeof(arr1)/sizeof(arr1[0]) ;

Copy<int>(arr2, arr1, sz, TypeTraits<int>::isPodType());

float arr3[] = {1.0, 2.1};// float 没有特化 走默认的TypeTraits

float arr4[2];

sz = sizeof(arr3)/sizeof(arr3[0]);

Copy<float>(arr4, arr3, sz, TypeTraits<float>::isPodType());

}

#endif //==========================

//============ 1 萃取  Copy的第2种方法 ==============

//               用模板函数

template<typename T>

void Copy(T* dst, const T* src, size_t size)

{

if(TypeTraits<T>::isPodType().Get())//使用类型isPodType构造匿名函数isPodType()

{

//cout<<"__TrueType"<<typeid(T).name()<<endl;

memcpy(dst, src, size * sizeof(T));

}

else

{

//cout<<"FalseType"<<typeid(T).name()<<endl;

for (size_t i = 0; i < size; i++)

{

dst[i] = src[i];

}

}

}

#endif

//---------------   seq_list_by_cuiqu.cpp--------

#define _CRT_SECURE_NO_WARNINGS 1

#include "Copy.h"

template <typename T>

class SeqList

{

public:

SeqList();

SeqList(const SeqList& s);

~SeqList();

void PushBack(const T& d);

void PopBack();

void PushFront(const T& d);

void PopFront();

int Find(const T& d);

void Reverse();

void Insert(int pos, const T& d);

void sort();

SeqList& operator=(const SeqList& s);

void Print()

{

int i = 0;

for(i = 0; i < _size; i++)

{

cout<<_data[i]<<"  ";

}

cout<<endl;

}

private:

void _check_capacity()

{

if(_size == _capacity)

{

T* tmp = new T[2 * _capacity + 3];

//======注意 1 memcpy()浅拷贝问题 ===================

//对于含有指向动态开辟空间的类

//memcpy() 会出现浅拷贝现象 导致两个类的成员指针

//指向同一块空间 析构两次时导致【程序崩溃】

//比如 string类 内部含有这样一个指针

//当然 还有初始预留的空间 如果字符串没有超过预留空间

//指向动态空间的指针为空 用memcpy()也没事

//但当这个指针指向空间是 一等会由于浅拷贝导致析构

//失败的

//==============================================

// memcpy(tmp, _data, _size * sizeof(T));

//===========================================

//解决方法

//利用 string类 自带的operator=()一个一个复制

//避免出现浅拷贝现象

//不过memcpy()也有优点 那就是效率高

//===========================================

/*for(int i = 0; i < _size; i++)

{

tmp[i] = _data[i];

}*/

// 更高效 使用【类型萃取】 对于可以使用memcpy的类型使用memcpy

// 对于不可以使用memcpy的 使用 循环一个一个赋值 增强效率

// 因为memcpy效率比较高

Copy(tmp, _data, _size);

delete[] _data;

_data = tmp;

_capacity = 2 * _capacity + 3;

}

}

private:

int _size;

int _capacity;

T* _data;

};

//=================注意2 默认拷贝函数出现浅拷贝问题 ===========

//这要写 拷贝构造 防止出现浅拷贝问题

// 例如对于string这种含有指向动态开辟空间 的 指针成员

template <typename T>

SeqList<T>::SeqList(const SeqList<T>& s)

{

_data = new T[s._size];

int i = 0;

for(i = 0; i < s._size; i++)

{

_data[i] = _data[i];

}

_size = s._size;

_capacity = _size;

}

template <typename T>

SeqList<T>::SeqList()

:_size(0)

,_capacity(3)

,_data(new T[_capacity])//注意:声明类变量时要先声明_capacity 再声明_data

{

//cout<<typeid(_capacity).name() <<endl;

//cout<<"SeqList()"<<endl;

}

template <typename T>

SeqList<T>::~SeqList()

{

if (_data != NULL)

{

delete[] _data;

_data = NULL;

}

}

template <typename T>

void SeqList<T>::PushBack(const T& d)

{

_check_capacity();

_data[_size] = d;

_size++;

}

template <typename T>

void SeqList<T>::PopBack()

{

if(_size > 0)

{

_size--;

}

}

template <typename T>

void SeqList<T>::PushFront(const T& d)

{

_check_capacity();

int i = _size;

while(i)

{

_data[i] = _data[i - 1];

i--;

}

_data[0] = d;

_size++;

}

template <typename T>

void SeqList<T>::PopFront()

{

int i = 0;

for(i = 0; i < _size - 1; i++)

{

_data[i] = _data[i + 1];

}

_size--;

}

template <typename T>

SeqList<T>& SeqList<T>::operator=(const SeqList& s)//注意用SeqList<T>&

{

if(this != &s)

{

delete[] _data;

_data = new T[s._capacity];

memcpy(_data, s._data, s._size * sizeof(T));

_size = s._size;

_capacity = s._capacity;

}

return *this;

}

template <typename T>

int SeqList<T>::Find(const T& d)

{

int i = 0;

for (i = 0; i < _size; i++)

{

if(_data[i] == d)

{

return i;

}

}

return -1;

}

template <typename T>

void SeqList<T>::Reverse()

{

int left = 0;

int right = _size - 1;

while(left < right)

{

swap(_data[left], _data[right]);

left++;

right--;

}

}

template <typename T>

void SeqList<T>::Insert(int pos, const T& d)

{

if(pos < 0 || pos > _size)

{

return;

}

_check_capacity();

int i = _size;

_size++;

while(i > pos)

{

_data[i] = _data[i - 1];

i--;

}

_data[pos] = d;

}

template <typename T>

void SeqList<T>::sort()

{

int i = 0;

for(i = 0; i < _size; i++)

{

bool flag = true;

for(int j = 0; j < _size - i - 1; j++)

{

if(_data[j] > _data[j + 1])

{

T temp = _data[j];

_data[j] = _data[j + 1];

_data[j + 1] = temp;

flag = false;

}

}

if(flag)

{

return;

}

}

}

int main()

{

{

//SeqList<int> s1;

/*s1.PushBack(1);

s1.PushBack(2);

s1.PushBack(3);

s1.PushBack(4);

s1.Print();

s1.PopBack();

s1.Print();

s1.PopBack();

s1.Print();

s1.PopBack();

s1.Print();

s1.PopBack();

s1.Print();

s1.PopBack();

s1.Print();

s1.PopBack();

s1.Print();*/

//s1.PushFront(1);

//s1.PushFront(2);

//s1.PushFront(3);

//s1.PushFront(4);

//s1.Print();

//s1.PopFront();

//s1.Print();

//s1.PopFront();

//s1.Print();

//s1.PopFront();

//s1.Print();

//s1.PopFront();

//s1.Print();

//s1.PopFront();

//s1.Print();

//s1.PopFront();

//s1.Print();

/*SeqList<string> s2;

s2.PushBack("1");

s2.PushBack("11111112222222222");

s2.Print();*/

//s2.PushBack();

//s2.PushBack();

//s2.PushBack();

SeqList <string> s1;

s1.PushBack("11111");

s1.PushBack("222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222");

s1.PushBack("33333");

s1.PushBack("44444");

s1.PushBack("44444");

/*s1.PushBack("44444");

s1.PushBack("44444");

s1.PushBack("44444");

s1.PushBack("44444");

s1.PushBack("44444");

s1.PushBack("44444");*/

s1.Print();

SeqList <int> s3;

s3.PushBack(1);

s3.PushBack(2);

s3.PushBack(3);

s3.PushBack(4);

s3.PushBack(5);

s3.Print();

//SeqList <string> s2(s1);

//s2 = s1;

//s2.Print();

/*s1.PushBack(4);

s1.PushBack(3);

s1.PushBack(2);

s1.PushBack(1);

s1.Print();*/

/*s1.sort();

s1.Print();

cout<<s1.Find(3)<<endl;

s1.Insert(s1.Find(3),4);

s1.Print();*/

/*SeqList<int> s2 = s1;

s2.Print();*/

}

//test2();

getchar();

return 0;

}

//====================================================

//(2) 容器适配器

容器适配器 允许 模板参数 是模板类的类类型

// Container 适配器练习

//template <typename T, typename Container>

//模板的模板参数

template <typename T, template<class> class Container = SeqList>

class Stack

{

public:

void Push(const T& d)

{

con.PushBack(d);

}

void Pop()

{

con.PopBack();

}

private:

Container<T> con;

};

int main()

{

//SeqList<int> seq;

Stack<int, SeqList> stack1;

Stack<int> stack2;

stack1.Push(1);

stack1.Pop();

return 0;

}

#endif

//#include <vector>

//int main()

//{

// int b;

// vector<int> vec;

// vec.push_back(1);

// vec.push_back(2);

// return 0;

//}

//#include <list>

//int main()

//{

// list<string> vec;

// vec.push_back("aaaaaa");

// vec.push_back("bbbbbbbb");

// return 0;

//}

//小知识点

//========隐式转换

class D

{

public:

explicit D(int d)

:_d(d)

{cout<<"D()"<<endl;}

private:

int _d;

};

int main()

{

D d = 1; //防止使用D(int d)构造函数 隐式转换 可以使用关键字explicit 阻止隐式转换

getchar();

return 0;

}

时间: 2024-10-12 17:15:40

C++ 模板 之 类型萃取 与 容器适配器的相关文章

c++ 类型萃取(模板类型 运用)

//类型萃取 #pragma once #include<iostream> using namespace std; struct __TrueType//定义类 普通类型(基本类型的) { bool Get() { return true; } }; struct __FalseType//定义类 非基本类型 { bool Get() { return false; } }; template <class _Tp>//模板类 (类型萃取) struct TypeTraits 

C++_模板类与类型萃取技术

在声明变量,函数,和大多数其他类型实体的时候,C++要求我们使用指定的类型.然而,有许多代码,除了类型不同之外,其余部分看起来都是相同的,比如,下面这个例子: bool IsEqual (int left, int right) {     return left == right; } bool IsEqual (const string& left , const string& right) {     return left == right; } void test() {   

【干货】C++通过模板特化实现类型萃取实例--实现区分基本类型与自定义类型的memcpy

类型萃取是一种常用的编程技巧,其目的是实现不同类型数据面对同一函数实现不同的操作,如STL中cout的实现,它与类封装的区别是,我们并不用知道我们所调用的对象是什么类型,类型萃取是编译器后知道类型,先实现,而类的封装则是先定义类型,后实现方法.在这里我们可以用模板的特化实现其编程思想. 我们以memcpy为例,当我们拷贝的是基本类型时,只用拷贝所传递指针上的数据,如果是string类型呢,我们则需要在堆上开辟空间,所传递的指针如果被直接复制,则有可能(vs下的string类型的实现原理是若字符串

通过模板的特化实现 简单的类型萃取 实现memcppy时候对于特殊类型如string类的拷贝。

C++怎样识别一个对象的类型? typeid可以获取到一个类型的名称,但是不能拿来做变量的声明. [POD类型萃取] // // POD: plain old data 平凡类型(无关痛痒的类型)--基本类型 // 指在C++ 中与 C兼容的类型,可以按照 C 的方式处理. //#include<iostream> #include<string> using namespace std; struct __TrueType {  bool Get()  {   return tr

STL的迭代器和类型萃取

今天就可以把STL库中迭代器的实现,和类型萃取好好整理一下了 迭代器的设计思维是STL的关键所在,在STL的实际运用和泛型思维,迭代器都扮演着十分重要的角色,STL力求把数据容器和算法的概念分开来,于是就有了STL的两大部分,容器(container)和泛型算法(algorithms),泛型算法有很多参数都是迭代器. 举一个栗子!泛型算法find()的实现! 1 template<class InputIterator, class T> 2 InputIterator find(InputI

类型萃取

类型萃取是实现不同类型数据面对同一函数实现不同的操作,它与类封装的区别是:并不用知道所调用的对象是什么类型,类型萃取是编译后知道类型,先实现:而类的封装则是先定义类型,后实现方法. 类型分为基本类型(POD),和自定义类型. 在这里用模板的特化实现其编程思想: 以memcpy为例,当拷贝的是基本类型(POD)时,只用拷贝所传递指针上的数据,如果是string类型,则需要在堆上开辟空间,所传递的指针如果被直接复制,则有可能(vs下的string类型的实现原理是若字符串不长则以数组保存,若字符串过长

第17课 类型萃取(1)_基本的type_traits

1. type_traits类型萃取 (1)type_traits通过定义一些结构体或类,并利用模板类特化和偏特化的能力,给类型赋予一些特性,这些特性根据类型的不同而异.在程序设计中可以使用这些traits来判断一个类型的一些特性,引发C++的函数重载机制,实现同一种操作因类型不同而异的效果. (2)type_traits提供了丰富的编译期计算.查询.判断.转换和选择的帮助类. (3)type_traits的类型选择功能,在一定程序上可以消除冗长的switch-cast或if-else的语句.提

SGI-STL简记(三)-构造、类型萃取特性、未初始化解析

stl_construct.h : 提供多种构造器.销毁器模板函数: 构造器construct提供了给定值构造和默认构造方式,通过调用重载函数_Construct实现: 销毁器destroy提供了销毁指针和迭代器的方式,通过调用重载函数_Destroy实现: _Construct:通过“放置”new,构造实现: _Destroy:通过调用模板类型对象析构函数实现,对于迭代器器方式,则通过__destroy(内部通过__destroy_aux)遍历销毁,因内置数据类型不需要销毁, 故内部需要判断是

头一回发博客,来分享个有关C++类型萃取的编写技巧

废话不多说,上来贴代码最实在,哈哈! 以下代码量有点多,不过这都是在下一手一手敲出来的,小巧好用,把以下代码复制出来,放到相应的hpp文件即可,VS,GCC下均能编译通过 1 #include<iostream> 2 #include "../../traits/traits.hpp" 3 4 5 using namespace std; 6 7 8 int show(char i, int j) 9 { 10 return 1; 11 } 12 13 struct Stu