模板特化

在将萃取机制之前,先要说明模板特化

当有两个模板类,一个是通用泛型模板,一个是特殊类型模板,如果创建一个特殊类型的对象,会优先调用特殊的类型模板类,例如:

template <typename T>	//泛型模板
class MyClass
{
public:
MyClass()
{
cout << "T MyClass!" << endl;
}
~MyClass()
{
cout << "~T MyClass!" << endl;
}
}; template<>
class MyClass<int> //全特化模板
{
public:
MyClass()
{
cout << "int MyClass!" << endl;
}
~MyClass()
{
cout << "~int MyClass!" << endl;
}
}; int main()
{
MyClass<char> mc0;
MyClass<int> mc1;
return 0;
}

运行结果:

T MyClass!
int MyClass!
~int MyClass!
~T MyClass!

萃取机制

现在举一系列例子来说明萃取机制

现在有两个类,需要完成相同的功能GetSum返回求和值

//int类型
class IntArray
{
public:
IntArray()
{
a = new int[10];
for (int i = 0; i < 10; ++i)
{
a[i] = i + 1;
}
}
~IntArray()
{
delete[] a;
} int GetSum(int times) //对整数求和
{
int sum = 0;
for (int i = 0; i < 10; ++i)
sum += a[i];
cout << "int sum=" << sum << endl;
return sum * times;
}
private:
int *a;
}; //Float类型
class FloatArray
{
public:
FloatArray()
{
f = new float[10];
for (int i = 1; i <= 10; ++i)
{
f[i - 1] = 1.0f / i;
}
}
~FloatArray()
{
delete[] f;
}
float GetSum(float times) //对浮点数求和
{
float sum = 0.0f;
for (int i = 0; i < 10; i++)
sum += f[i];
cout << "float sum=" << sum << endl;
return sum * times;
}
private:
float* f;
};

我们可以看到,这样写代码冗余度很高,一部分功能比如GetSum函数,两个类都有,能不能用一个类完成?

先定义一个类,通过泛型,调用对应对象的GetSum函数得到结果。

template<class T>
class Apply
{
public:
float GetSum(T& t, float inarg)
{
return t.GetSum(inarg);
}
};

这种方法不能完全解决我们的问题(函数返回值和参数类型固定,就会导致异常),如何解决变化的输入输出参数?traits技术就能解决问题。

template<class T>	//可以什么都不用写,说明定义了一个模板类
class NumTraits
{}; //模板特化IntArray
template<>
class NumTraits<IntArray>
{
public:
typedef int resulttype;
typedef int inputargtype;
};
//模板特化FloatArray
template<>
class NumTraits<FloatArray>
{
public:
typedef float resulttype;
typedef float inputargtype;
}; template<class T>
class Apply2
{
public:
NumTraits<T>::resulttype GetSum(T& obj, NumTraits<T>::inputargtype inputarg)
{
return obj.GetSum(inputarg);
}
}; int main()
{
IntArray intary;
FloatArray floatary;
Apply2<IntArray> ai2; //采用萃取
Apply2<FloatArray> af2; //采用萃取
cout << "2整型数组的和3倍:" <<ai2.GetSum(intary,3) << endl; //返回整形
cout << "2浮点数组的和3.2倍:" << af2.GetSum(floatary,3.2f) << endl; //返回浮点型
return 0;
}

为什么两个类中都定义了resulttype和inputargtype,为什么要把返回类型、输入参数,都定义为相同的名称呢?因为为了编制模板类共同的调用接口做准备。

为了简化Apply2函数的定义形式,再次巧妙运用typedef进行定义,代码如下,与原始功能相同。

//泛型模板类
template<class T>
class NumTraits
{}; //可以什么都不用写,说明定义了一个模板类 template<> //模板特化
class NumTraits<IntArray>
{
public:
typedef int resulttype;
typedef int inputargtype;
}; template<> //模板特化
class NumTraits<FloatArray>
{
public:
typedef float resulttype;
typedef float inputargtype;
}; template<class T>
class Apply2
{
public:
typedef NumTraits<T>::resulttype result;
typedef NumTraits<T>::inputpara input; result GetSum(T& obj, intput inputarg)
{
return obj.GetSum(inputarg);
}
};

总结

萃取机制在STL中被广泛运用,借助模板特化和和typedef可以将接口做到通用,降低了代码的冗余度,提高了代码的复用

STL 萃取(Traits)机制剖析的更多相关文章

  1. STL源代码分析--萃取编程(traits)技术的实现

    1.为什么要出现? 依照默认认定.一个模板给出了一个单一的定义,能够用于用户能够想到的不论什么模板參数!可是对于写模板的人而言,这样的方式并不灵活.特别是遇到模板參数为指针时,若想实现与类型的參量不一 ...

  2. 【STL 源码剖析】浅谈 STL 迭代器与 traits 编程技法

    大家好,我是小贺. 点赞再看,养成习惯 文章每周持续更新,可以微信搜索「herongwei」第一时间阅读和催更,本文 GitHub : https://github.com/rongweihe/Mor ...

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

    废话不多说,上来贴代码最实在,哈哈! 以下代码量有点多,不过这都是在下一手一手敲出来的,小巧好用,把以下代码复制出来,放到相应的hpp文件即可,VS,GCC下均能编译通过 #include<io ...

  4. STL--迭代器设计原则和萃取机制(Traits)

    title: C++ STL迭代器设计原则和萃取机制(Traits) date: 2019-12-23 15:21:47 tags: STL C/C++ categories: STL 迭代器 (it ...

  5. STL的迭代器和类型萃取

    今天就可以把STL库中迭代器的实现,和类型萃取好好整理一下了 迭代器的设计思维是STL的关键所在,在STL的实际运用和泛型思维,迭代器都扮演着十分重要的角色,STL力求把数据容器和算法的概念分开来,于 ...

  6. 类型萃取(type traits)

    1. 类型萃取的作用 类型萃取使用模板技术来萃取类型(包含自定义类型和内置类型)的某些特性,用以判断该类型是否含有某些特性,从而在泛型算法中来对该类型进行特殊的处理用来提高效率或者其他.例如:在STL ...

  7. traits编程---萃取容器中迭代器的类型等

    可以直接利用STL中定义好的traits_iterator来萃取 /*特性萃取器*/ template <class unknown_class> struct unknown_class ...

  8. C++之萃取技术(traits)

    为什么需要类型萃取(特化) 前面我们提到了迭代器,它是一个行为类似于smart pointer之类的东西,主要用于对STL容器中的对象进行访问,而且不暴露容器中的内部结构,而迭代器所指对象的型别称为该 ...

  9. C++11中的技术剖析(萃取技术)

    从C++98开始萃取在泛型编程中用的特别多,最经典的莫过于STL.STL中的拷贝首先通过萃取技术识别是否是已知并且支持memcpy类型,如果是则直接通过内存拷贝提高效率,否则就通过类的重载=运算符,相 ...

随机推荐

  1. JMeter接口测试-JMeter+ant实现接口自动化测试

    前言 小伙伴们,用python做接口自动化是不是写代码比较繁琐,而且没有python代码基础的小伙伴根本无从下手对吧!今天我们来学习一下如何使用JMeter工具实现接口自动化测试. 1.安装JDK,配 ...

  2. 安装TensorFlow失败

    ERROR: Could not find a version that satisfies the requirement tensorflow==2.1.0 (from versions: non ...

  3. srpingboot web - 启动(3) 监听器

    接上一篇 一. getRunListeners() 在run() 方法中调用了 getRunListeners(args) 方法, 先看一下这个方法干了什么 private SpringApplica ...

  4. (jsp+servlet+javabean )MVC架构

    MVC是三个单词的缩写,这三个单词分别为:模型.视图和控制. 使用的MVC的目的:在于将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式.比如Windows系统资源管理器文件夹内容的显示方 ...

  5. Microsoft.EntityFrameworkCore.Internal.ServiceProviderCache的类型初始值设定项引发异常。 ---> System.IO.FileLoadException: 未能加载文件或程序集

    场景: 安装程序到全新的环境的电脑时中(此时已经安装了能正常安装程序电脑的环境) 完整错误: Application_ThreadException:System.TypeInitialization ...

  6. Linux C语言 文件操作

    打开函数 fopen 的原型如下. FILE * fopen(char *filename, char *mode); 返回值:打开成功,返回该文件对应的 FILE 类型的指针:打开失败,返回 NUL ...

  7. new SparkContext()发生错误java.lang.NoSuchMethodError: scala.Predef

    参考:https://blog.csdn.net/weixin_40137479/article/details/80320324 new SparkContext(conf)发生错误: Except ...

  8. 在bootstrap的column中的formatter里不能传递row参数吗?

    row 是一个对象  你需要把它转成字符串用JSON.stringify(row),这样就是字符串了,但是还有问题,你需要给加密一下encodeURI(JSON.stringify(row)),然后方 ...

  9. liunx下安装Docker

    1.安装并启动docker 1.检查内核版本,必须是3.10及以上uname -r2.安装docker yum install docker命令安装(需要联网) [root@localhost ~]# ...

  10. C语言链表的中间结点

    给定一个带有头结点 head 的非空单链表,返回链表的中间结点. 如果有两个中间结点,则返回第二个中间结点. 示例 1: 输入:[1,2,3,4,5]输出:此列表中的结点 3 (序列化形式:[3,4, ...