模板特化

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

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

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. 方法(定义、调用、重载)—Java

    一. 什么是方法 不可能所有的功能都放到main中,需要定义其他方法完成指定功能,需要时调用方法即可 封装在一起来执行操作语句的集合,用来完成某个功能操作 封装在一起来执行操作语句的集合,用来完成某个 ...

  2. vue动画&过渡整理

  3. node常用模块汇总

    node常用模块汇总: 点击插件名字,查看使用文档 npm常用模块汇总 node常用模块汇总 gulp常用插件汇总 mkdirp:在node.js中像mkdir -p一样递归创建目录及其子目录

  4. VSCode部署JAVA项目出现The type java.lang.Object cannot be resolved

    如题,出现的原因是这样的:我将mac系统上的eclipse项目复制到了ubuntu环境下,通过vscode的远程功能连接ubuntu. 然后项目上就出现了各种报错,显示The type java.la ...

  5. Parity game POJ - 1733 带权并查集

    #include<iostream> #include<algorithm> #include<cstdio> using namespace std; <& ...

  6. C# ASCII码的转换、转义字符、对照表

    var splitStr = new byte[] { 0x05, 0x0D, 0x0A };//var splitStr = new byte[] { 5, 13, 10 };这样写也可以 var ...

  7. 在 React 中使用 Typescript

    前言 用 Typescript 写 React 可比写 Vue 舒服太多了,React 对 ts 的支持可谓天生搭档,如果要用 ts 重构项目,不像 Vue 对项目破坏性极大,React 可以相对轻松 ...

  8. Mysql快速入门(三)

    MySQL性能优化之查看执行计划explain 介绍: (1).MySQL 提供了一个 EXPLAIN 命令, 它可以对 SELECT 语句进行分析, 并输出 SELECT 执行的详细信息, 以供开发 ...

  9. Educational Codeforces Round 65 (Rated for Div. 2)B. Lost Numbers(交互)

    This is an interactive problem. Remember to flush your output while communicating with the testing p ...

  10. Cow Contest POJ - 3660 floyd传递闭包

    #include<iostream> #include<cstring> using namespace std; ,INF=0x3f3f3f3f; int f[N][N]; ...