C++泛型程序设计---算法和提升
算法和提升
算法:所谓算法就是一个求解问题的过程或公式,即,通过一个有穷的计算序列生成结果。
函数模板就是普通函数的泛化:它能对多种数据类型执行动作,并且能用以参数方式传递来的各种操作实现要执行的工作,函数模板通常也称为算法。
提升:从一个(多个可能更好)具体的实例中泛化出一个算法,使之能适用于最大(但合理)范围的实参类型,即,限制一个算法(或一个类)只依赖必要的属性。
提升算法是一个由具体到抽象的过程,最重要的一点是保持性能并注意如何做才是合理的,如果试图覆盖所有可能的类型和操作,可能会把泛化推到一个不合理的程度。因此试图在缺乏具体实例的情况下直接从基本原理进行抽象,通常会使代码臃肿不堪,难以使用。
以下展示从一个具体实例提升出算法的过程:
//计算实参数组中double值的和
double add_double(double *array, int n)
{
double sum{0};
for(int i = 0; i < n; ++i)
{
sum = sum + array[i];
}
return sum;
}
//计算vector<int>中所有int值的和
int add_vector(const std::vector<int> &vec)
{
int sum{0};
for(auto iter = vec.cbegin(); iter != vec.cend(); ++iter)
{
sum += *iter;
}
return sum;
}
以上代码给出了两个具体的算法,现在以这两个具体的算法未起点,逐步设计出一个通用的算法。
先确定一个抽象的目标:
- 不再明确说明元素是double还是int。
- 不再明确说明是数组还是向量。
以下为第一个抽象版本:
template<typename Iter, typename Val = double>
Val sum_v1(Iter first, Iter last) noexcept
{
Val sum = 0;
while(first != last)
{
sum = sum + (*first);
++first;
}
return sum;
}
//测试
vector<int> vec = {200, 2, 3, 4};
int sum1 = sum_v1<vector<int>::iterator, int>(vec.begin(), vec.end()); //sum1 = 209
double ad[] = {100.0, 2, 3, 4};
double sum2 = sum_v1(ad, ad + 4); //sum2 = 109
以上抽象出了一个通用版本, 但是类型参数Val不能自动推到获得,显式的指定Val有点不友好。
下面针对Val类型参数、运算符做进一步抽象
template<typename Iter, typename Val, typename Operator>
Val sum_v2(Iter first, Iter last, Val sum, Operator opr) noexcept
{
while(first != last)
{
sum = opr(sum, *first);
++first;
}
return sum;
}
//测试
vector<int> vec = {200, 2, 3, 4};
int sum = sum_v2(vec.begin(), vec.end(), 0, std::plus<int>());
double ad[] = {100.0, 2, 3, 4};
double product = sum_v2(ad, ad + 4, 1.0, std::multiplies<double>());
标准库对一些常见的运算,如plus、minus、multiplies,提供了对应的函数对象,可以作为实参。
设计算法最重要的指导原则是:在从具体实例提升算法的过程中,增加的特性(符号或运行时开销)不能损害算法的使用。
以下是标准库提供的plus函数对象
template<class _Ty = void>
struct plus
{
// functor for operator+
typedef _Ty first_argument_type;
typedef _Ty second_argument_type;
typedef _Ty result_type;
constexpr _Ty operator()(const _Ty& _Left, const _Ty& _Right) const
{
// apply operator+ to operands
return (_Left + _Right);
}
};
template<>
struct plus<void>
{
// transparent functor for operator+
typedef int is_transparent;
template<class _Ty1, class _Ty2>
constexpr auto operator()(_Ty1&& _Left, _Ty2&& _Right) const
-> decltype(static_cast<_Ty1&&>(_Left) + static_cast<_Ty2&&>(_Right))
{
// transparently apply operator+ to operands
return (static_cast<_Ty1&&>(_Left) + static_cast<_Ty2&&>(_Right));
}
};
C++泛型程序设计---算法和提升的更多相关文章
- C++学习笔记53:泛型程序设计与C++标准模板库
泛型程序设计的基本概念 编写不依赖于具体数据类型的程序 将算法从特定的数据结构中抽象出来,成为通用的 C++模板为泛型编程程序设计奠定了关键的基础 模型:符合一个概念的数据类型称为该概念的模型,例如: ...
- 8、泛型程序设计与c++标准模板库1、泛型程序设计的概念和术语
有效地利用已有的成果,将经典的.优秀的算法标准化.模块化,从而提高软件的生产率,是软件产业化的需求,为了实现这一需求,不仅需要面向对象设计思想,而且需要泛型程序设计思想. c++语言提供的标准模板库( ...
- C++ 泛型程序设计与STL模板库(1)---泛型程序设计简介及STL简介与结构
泛型程序设计的基本概念 编写不依赖于具体数据类型的程序 将算法从特定的数据结构中抽象出来,成为通用的 C++的模板为泛型程序设计奠定了关键的基础 术语:概念 用来界定具备一定功能的数据类型.例如: 将 ...
- 谈下程序设计算法的准备心得与体会-nCov隔离也许帮你提升能力
最近武汉的n-Cov使得大家只能在家办公了. 在家里的感受是什么样的呢? 1.上班的时候一直在奔跑,现在总算可以有集中的时间来思考一些之前一直没能好好整理的内容 2.时间变得自己可以掌控,优先级有自己 ...
- Java基础语法<十二> 泛型程序设计
1 意义 泛型程序设计意味着编写的代码可以被很多不同类型的对象所重用. 常见应用 : ArrayList 2 K T V E ? object等的含义 类型变量使用大写形式 E – Element ( ...
- Java核心技术第八章——泛型程序设计(1)
1.泛型程序设计 泛型程序设计意味着编写的代码可以被很多不同类型的对象所重用.例如:不希望为了聚集String和Integer对象分别设计不同的类.(个人觉得此处说的聚集译为:创建一个对象,属性可以为 ...
- Java核心技术卷一基础知识-第12章-泛型程序设计-读书笔记
第12章 泛型程序设计 本章内容: * 为什么要使用泛型程序设计 * 定义简单泛型类 * 泛型方法 * 类型变量的限定 * 泛型代码和虚拟机 * 约束与局限性 * 泛型类型的继承规则 * 通配符类型 ...
- c/c++ 通用的(泛型)算法 之 只读算法,写算法,排序算法
通用的(泛型)算法 之 只读算法,写算法,排序算法 只读算法: 函数名 功能描述 accumulate 求容器里元素的和 equal 比较2个容器里的元素 写算法 函数名 功能描述 fill 用给定值 ...
- c/c++ 通用的(泛型)算法 generic algorithm 总览
通用的(泛型)算法 generic algorithm 总览 特性: 1,标准库的顺序容器定义了很少的操作,比如添加,删除等. 2,问题:其实还有很多操作,比如排序,查找特定的元素,替换或删除一个特定 ...
随机推荐
- POJ 3275 Ranking the cows ( Floyd求解传递闭包 && Bitset优化 )
题意 : 给出 N 头牛,以及 M 个某些牛之间的大小关系,问你最少还要确定多少对牛的关系才能将所有的牛按照一定顺序排序起来 分析 : 这些给出的关系想一下就知道是满足传递性的 例如 A > B ...
- IoC容器简介
官网说明: 在核心的第7章节 1 Spring IoC 容器和 beans 简介 本章介绍了 Spring Framework implementation of the Inversion of C ...
- hdu_3466(01背包)
其实,就是让C商品的q不等于p,其他都相同,这时,你就会发现如果要买C商品的话,肯定得先买C商品,因为买C商品的代价最大.所以,我们可以按照qi-pi的顺序来确定大顺序.这里我们还可以用更严谨的方式来 ...
- 【Leetcode】判断平面中1个点是否落在三角形内
参考资料: 题目: https://blog.csdn.net/dongtinghong/article/details/78657403 符号重载: https://blog.csdn.net/cd ...
- Redis、Nginx加入启动命令
1.redis加入系统启动命令 vim /etc/init.d/redis #!/bin/sh #chkconfig: 2345 80 90 # Simple Redis init.d script ...
- SQL server 从创建数据库到查询数据的简单操作
目录. 创建数据库 创建表 插入数据 查询 1.创建数据库 --创建数据库 create database db_Product go --使用数据库use db_Productgo 2.创建表 -- ...
- 使用SharpZIpLib写的压缩解压操作类
使用SharpZIpLib写的压缩解压操作类,已测试. public class ZipHelper { /// <summary> /// 压缩文件 /// </summary&g ...
- python jieba分词(结巴分词)、提取词,加载词,修改词频,定义词库 -转载
转载请注明出处 “结巴”中文分词:做最好的 Python 中文分词组件,分词模块jieba,它是python比较好用的分词模块, 支持中文简体,繁体分词,还支持自定义词库. jieba的分词,提取关 ...
- 浏览器默认样式及reset
写在前面 首先纠正一个易错概念.div并非生来就是块元素,而是每个浏览器都有一套默认的css样式(优先级最低),默认样式里会把div设置成display: block;还有margin,padding ...
- 如何设置linux bash终端的字符显示内容和颜色?
通常linux有1-6个字符终端 tty, 有1个图形终端. 通常用 ctrl+alt+f1 到f6是字符终端, ctrl+alt+f7为图形终端, 但是, 也有不一样的, 如: fedora的4.0 ...