SGISTL源码探究-仿函数

FPGA高速接口Aurora8B/10B协议实战:从IP核配置到数据流优化 本文详细介绍了FPGA高速接口Aurora8B/10B协议的实战应用,从IP核配置到数据流优化的全流程。通过Aurora8B/10B协议,开发者可以在FPGA间实现高效的数据传输,适用于高速接口设计。文章涵盖了协议基础、IP核配置、AXI4-Stream接口实战技巧以及性能优化策略,帮助读者快速掌握这一关键技术。 阅读详情

前言

本小节将介绍STL六大组件之一的仿函数(又称函数对象),在前面分析算法部分时,我们其实已经见识到了仿函数的大量使用(各算法的另一个版本,传入comp仿函数)。关于仿函数的实现,其实就是重载了()运算符,然后调用,所以又称函数对象。接下来我们就来分析该部分。

仿函数

虽然函数指针也可以完成将各种操作当作参数传入,但是之所以出现了仿函数,是因为函数指针并不能满足STL对抽象的要求,也不能和其他组件很好的搭配。

SGISTL自带了一部分仿函数,都在stl_function.h中,如果要使用仿函数,则需要引入头文件functional。这里给出一个简单的例子:

#include <iostream>
#include <functional>
using namespace std;

int main()
{
    int i = 2, j = 8;
    multiplies<int> mul;  
    cout << mul(i, j) << endl;  //调用()操作符
    cout << minus<int>()(i, j) << endl; //产生一个临时无名对象调用()操作符
    return 0;
}

上面使用的两个仿函数的源码实现如下:

//可见就只是重载了()操作符
//不过它们都继承了binary_function
//这个基类的作用我们等下分析
template <class T>
struct minus : public binary_function<T, T, T> {
    T operator()(const T& x, const T& y) const { return x - y; }
};

template <class T>
struct multiplies : public binary_function<T, T, T> {
    T operator()(const T& x, const T& y) const { return x * y; }
};

STL的仿函数按照操作数的个数分类分为一元和二元仿函数;按照功能来分类,可以分为算术运算、关系运算、逻辑运算三类。上面的这个例子中,继承的binary_function其实是代表该运算是二元运算,并且接着的三个模板参数分别代表两个参数的类型以及返回值的类型,这样做的目的都是为了可被函数配接器配接。

一元仿函数和二元仿函数的基类
//一元仿函数的基类
template <class Arg, class Result>
struct unary_function {
  //声明了参数以及返回值类型的别名
  typedef Arg argument_type;
  typedef Result result_type;
};

//二元仿函数的基类
template <class Arg1, class Arg2, class Result>
struct binary_function {
  //声明了参数以及返回值类型的别名
  typedef Arg1 first_argument_type;
  typedef Arg2 second_argument_type;
  typedef Result result_type;
};
与配接器的联系

而配接器就可以利用定义的这些相应型别完成和其仿函数不同的功能。
为了帮助理解,接下来举个例子

//仿函数配接器,利用仿函数改变一下设计变成求逻辑相反数(为true则返回false,为false返回true)
template <class Predicate>
class unary_negate
  : public unary_function<typename Predicate::argument_type, bool> {
protected:
  //仿函数
  Predicate pred;
public:
  explicit unary_negate(const Predicate& x) : pred(x) {}
  //利用继承的unary_negate里面typedef的参数类型获取参数类型
  bool operator()(const typename Predicate::argument_type& x) const {
    return !pred(x);
  }
};

就这样通过原来的仿函数为基础改变了下设计形成另一个仿函数(此时应该称为仿函数配接器了),这就是继承那两个基类的作用,获取到参数及返回值的类型,这个做法在仿函数配接器里面经常可见,而且可以看到unary_negate还继承了unary_function,证明其他的仿函数配接器还可以通过改变它来完成另外的功能,就像搭积木一样。这是函数指针无法完成的。

stl中各仿函数的实现

stl中实现了一部分常用的仿函数,以下按照仿函数的功能进行分类分析。

  • 算术类:

    1. 加法:

      template <class T>
      struct plus : public binary_function<T, T,  T> {
      T operator()(const T& x, const T& y) const { return x + y; }
      };
    2. 减法

      template <class T>
      struct minus : public binary_function<T, T, T> {
      T operator()(const T& x, const T& y) const { return x - y; }
      };
    3. 乘法

      template <class T>
      struct minus : public binary_function<T, T, T> {
      T operator()(const T& x, const T& y) const { return x - y; }
      };
    4. 除法

      template <class T>
      struct divides : public binary_function<T, T, T> {
      T operator()(const T& x, const T& y) const { return x / y; }
      };
    5. 取模

      template <class T>
      struct modulus : public binary_function<T, T, T> {
      T operator()(const T& x, const T& y) const { return x % y; }
      };
    6. 求相反数(一元仿函数)

      template <class T>
      struct negate : public unary_function<T, T> {
      T operator()(const T& x) const { return -x; }
      };

      以上的仿函数都很简单,就是根据参数个数来继承unary_function或者binary_function。而仿函数的用途是与算法相搭配。

      这里举一个例子,
      比如我们之前分析power算法时,它的源码如下:

      template <class T, class Integer>
      inline T power(T x, Integer n)
      {
       //最后一个参数为乘法仿函数,参数类型及返回值类型都为T
       return power(x, n, multiplies<T>());
      }
      
      template <class T, class Integer, class MonoidOperation>
      T power(T x, Integer n, MonoidOperation op) {
      //任何数的0次方都为1,这是代表运算的证同元素,我们等下进行详细的分析
          if (n == 0)
              return identity_element(op);
          else {
            while ((n & 1) == 0) {
              n >>= 1;
              //调用传入的仿函数进行求解
              x = op(x, x);
            }
      
            T result = x;
            n >>= 1;
            while (n != 0) {
              //调用传入的仿函数进行求解
              x = op(x, x);
              if ((n & 1) != 0)
              //调用传入的仿函数进行求解
              result = op(result, x);
              n >>= 1;
            }
            return result;
          }
      }

      从中可以看到算法和仿函数之间的紧密搭配。

      证同元素:

      上面的power算法中当次方数n等于0时使用了identity_element(op)作为返回值。这点我们在当时分析power算法的时候并没有细讲,在这里补上这个坑。证同元素是指当数值A与该元素进行某种op运算得出的结果还是A自己时,此时该元素就是该op运算的证同元素。比如乘法的证同元素为1(任何数乘1都为本身),加法的证同元素为0(任何数加0都为本身)等。

  • 关系运算类:

    1. 等于

      template <class T>
      struct equal_to : public  binary_function<T, T, bool> {
        bool operator()(const T& x, const T& y) const { return x == y; }
      };
    2. 不等于

      template <class T>
      struct not_equal_to : public binary_function<T, T, bool> {
        bool operator()(const T& x, const T& y) const { return x != y; }
      };
    3. 大于

      template <class T>
      struct greater : public binary_function<T, T, bool> {
        bool operator()(const T& x, const T& y) const { return x > y; }
      };
    4. 大于等于

      template <class T>
      struct greater_equal : public binary_function<T, T, bool> {
        bool operator()(const T& x, const T& y) const { return x >= y; }
      };
    5. 小于

      template <class T>
      struct less : public binary_function<T, T, bool> {
        bool operator()(const T& x, const T& y) const { return x < y; }
      };
    6. 小于等于

      template <class T>
      struct less_equal : public binary_function<T, T, bool> {
        bool operator()(const T& x, const T& y) const { return x <= y; }
      };
  • 逻辑运算类:

    1. 逻辑与

      template <class T>
      struct logical_and : public binary_function<T, T, bool> {
        bool operator()(const T& x, const T& y) const { return x && y; }
      };
    2. 逻辑或

      template <class T>
      struct logical_or : public binary_function<T, T, bool> {
        bool operator()(const T& x, const T& y) const { return x || y; }
      };
    3. 逻辑非

      template <class T>
      struct logical_or : public binary_function<T, T, bool> {
        bool operator()(const T& x, const T& y) const { return x || y; }
      };
  • 证同、选择、投射

    以上三种仿函数,刚才了解了一下证同元素,而关于选择仿函数,它的作用是接受一个pair作为传入参数,并返回pair的第一个/第二个元素。关于投射仿函数,它的作用是返回第一个/第二个参数,忽略第二个/第一个参数。

    它们的实现如下:

    1. 证同:

      template <class T>
      struct identity : public unary_function<T, T> {
        const T& operator()(const T& x) const { return x; }
      };
    2. 选择:

      template <class Pair>
      struct select1st : public unary_function<Pair, typename Pair::first_type> {
        const typename Pair::first_type& operator()(const Pair& x) const
        {
          return x.first;
        }
      };
      
      template <class Pair>
      struct select2nd : public unary_function<Pair, typename Pair::second_type> {
        const typename Pair::second_type& operator()(const Pair& x) const
        {
          return x.second;
        }
      };
    3. 投射:

      template <class Arg1, class Arg2>
      struct project1st : public binary_function<Arg1, Arg2, Arg1> {
        Arg1 operator()(const Arg1& x, const Arg2&) const { return x; }
      };
      
      template <class Arg1, class Arg2>
      struct project2nd : public binary_function<Arg1, Arg2, Arg2> {
        Arg2 operator()(const Arg1&, const Arg2& y) const { return y; }
      };

小结

关于仿函数的分析就到此为止,其实实现的很简单也很基础,主要是为了配合STL其他组件进行使用。下一小节中我们将分析STL中最后一个组件配接器部分。

GitLab教程(四):分支(branch)和合并(merge) 命令进行合并时,Git具备一定的智能自动化处理能力:如果一个分支仅修改了文件A,而另一个分支独立地修改了文件B,Git能够无缝整合这些更改,自动完成合并过程——即最终的代码既包含了对A文件的修改也包含了对B文件的修改。同样地,若两个分支虽然都修改了同一个文件,但涉及的是文件中互不重叠的部分,比如一个改动发生在第一行,另一个则在第二行,Git同样能巧妙地自动合并这些非冲突性修改。获取了远程分支的最新变化,或者当你想要合并本地的一个分支到当前分支时,就会用到这个命令。,默认会尝试合并远程分支到当前分支。 阅读详情

相关推荐

给宇树Go2机器人装‘眼睛’:在Jetson Orin Nano上从零部署YOLOv5的保姆级避坑实录

本文详细介绍了在Jetson Orin Nano上为宇树Go2机器人部署YOLOv5视觉系统的完整流程,涵盖硬件选型、环境配置、模型优化及系统集成等关键步骤。针对机器人应用场景特有的离线部署、版本冲突和实时推理等挑战,提供了实用的解决方案和性能优化技巧,帮助开发者快速实现机器人的视觉能力升级。

weixin_29169505的博客 378

仿函数的用法

仿函数:仿函数又名函数对象:{    1、调用者:可以像函数一样被调用;    2、被调用者:以对象所定义的function call operator扮演函数的实质角色}仿函数的主要作用:以tempplate参数指定你要采取的策略。以sort()为例,其第一个版本是以operator &lt; 为排序时的元素位置调整依据,第二个版本则允许用户指定任何“操作”,务求排序后的两两相邻元素都能操作结果...

We_are_family678的博客 1730

golang 线上事故

golang 线上事故 最近公司要做大促的一些活动。并且单量,qps持续上涨。之前使用的是django python 语言做的一个服务端。目前已经部署的国家里面最多的国家会有300+个实例。大促期间还可能会增加一个实例数。这么多的实例部署,回滚的时间都会特变长,除了问题也不好定位。并且如此多的一个机器,连接数* 实例数也会导致DB等其他服务扛不住这么大的并发。所以决定上go服务解决性能问题。 ...

lcf枫的博客 1537

STL之仿函数实现详解

1、何为仿函数 仿函数的主要功能是为了搭配STL算法使用,单独使用仿函数的情况比较少。 仿函数(functors)在C++标准中采用的名称是函数对象(function objects)。仿函数主要用于STL中的算法中,虽然函数指针虽然也可以作为算法的参数,但是函数指针不能满足STL对抽象性的要求,也不能满足软件积木的要求–函数指针无法和STL其他组件搭配,产生更灵活变化。仿函数本质就是类重载了...

一个菜鸟的博客 2万+

vscode使用continue插件连接LM studio的模型

本文详细介绍了如何使用VSCode的Continue插件连接LM Studio模型。主要步骤包括:在LM Studio中加载模型并设置相关参数,启动API服务,修改Continue配置文件以集成LM Studio模型,并进行测试以验证连接是否成功。通过这些步骤,用户可以将LM Studio中的预训练模型与VSCode的Continue插件无缝对接,实现高效的自然语言处理和编程辅助功能。

weixin_43590837的博客 8628

IC面试常考题 Verilog三分频电路设计(占空比50%,三分之一,三分之二)

实现三分频电路最简单的是: 利用计数器实现。 时序图分析(本人比较懒,平常科研忙,所以直接手画时序图了,懒得用软件画了): 直接上图分析:利用计数器每隔三个周期信号翻转一次,同时在不同的计数下翻转得到的同步信号 clk_1和clk_2,再利用异或即可实现出一个不同占空比的三分频信号(同样的方法也可扩展到其他奇数分频设计中)。 例如占空比50%: module Div_three( input clk, input rst_n, output div_three ); reg

qq_41884662的博客 1万+

仿函数是什么?仿函数什么时候必须继承一元或者二元谓词

什么是仿函数?为什么有些仿函数必须要继承unary_function或者binary_function 仿函数的概念 使用起来像函数一样的东西,实际是一个对象 主要功能是为了搭配STL的算法 template<typename T> struct myPlus { T operator()(const T& a1, const T& a2) const { return a1 + a2; } }; void test05() { myPlus<int> .

zishuijing_dd的博客 629

儿童启蒙教育APP

pinyinList.add(createPinyin("a", "啊,像阿姨的阿", R.raw.pinyin_a));pinyinList.add(createPinyin("i", "衣,像衣服的衣", R.raw.pinyin_i));pinyinList.add(createPinyin("u", "乌,像乌鸦的乌", R.raw.pinyin_u));pinyinList.add(createPinyin("ü", "鱼,像小鱼的鱼", R.raw.pinyin_v));-- 固定竖屏 -->

寒寒豆豆软件公司的博客 166

仿函数

一、仿函数的简介 1、什么是仿函数 其实就是一个对象,这不过这个对象重载了operator( ),可以像函数一样使用它 2、仿函数出现的意义 要想然一个“操作”作为算法的参数,唯一的办法就是给这个操作设计为一个函数,然后将函数指针作为算法的一个参数; 或者为这个操作设计出一个仿函数,然后通过仿函数产生一个对象,然后将这个对象作为算法的一个操作 3、为什么有了函数指针还需要仿函数

Everlasting2016的博客 2082

MSVS C# Matlab的混合编程系列2 - 构建一个复杂(含多个M文件)的动态库:

本节我们尝试将一个有很多函数和文件的Matlab算法文件集成到C#的项目里面。

山云的专栏 2068

大数据Alluxio面试题及参考答案

Alluxio 在大数据生态里的定位是作为数据编排层,能在不同计算框架和存储系统之间起到桥梁的作用。它的核心功能在于加速数据访问,让大数据应用能够更高效地使用数据。Alluxio 把数据存储和数据处理分离开来,使计算框架可以在不考虑底层存储细节的情况下访问数据,这样就提高了系统的灵活性和可扩展性。Alluxio 和 HDFS 既存在关联又有区别。从关联方面来看,HDFS 是一种广泛使用的分布式文件系统,很多大数据应用都将其作为主要的数据存储系统。Alluxio 可以和 HDFS 集成,把 HDFS 当作底层

大模型大数据攻城狮的专栏 861

STL算法分析

STL power算法: template T power(T x ,Iteger n, MonoidOperation op){ if(n == 0) return identity_element(op); //证同元素,如果是0的话,代表加法的正同元素 else{ while((n & 1) == 0){ //n为偶数的时候

w1012747007的专栏 302

【ComfyUI】Flux 完整版文生图

本文介绍了一个基于Flux Dev的AI文生图全流程工作流,通过整合扩散模型、文本编码器和VAE解码器等核心组件,实现从文本到高清图像的端到端生成。工作流包含模型加载、条件构建、潜空间采样、图像解码和成果保存五个关键环节,支持高分辨率图像的细节还原和艺术风格塑造。应用场景涵盖艺术创作、内容生产、教学演示和科研数据准备等领域,适用于对画质和提示遵循性要求严格的场景。文章还提供了相关开发资源和学习教程链接,帮助用户深入理解AI绘图机制和实际应用。

Mr数据杨 1276

SGISTL源码探究-大根堆heap

前言小根堆和大根堆的概念在数据结构都讲过,等下简单的过一下就行了。在SGISTL的实现中,它并不作为一种容器,而是一系列的算法,用于给priority_queue提供支持,使优先级队列能够体现其优先级。 在SGISTL实现heap中,采用的数据结构并不是使用二叉树实现,而是采用隐式表达,即使用数组表示一个堆。能用数组表示这是因为堆总是一棵完全二叉树(没有节点漏洞):即若设二叉树的高度为h,除第 h

Move_now的博客 874

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

SGISTL源码-仿函数 笔记

本文是阅读SGISTL源码中关于functional相关文件所做的笔记

weixin_46065476的博客 208

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

SGISTL源码探究-vector容器(上)

前言vector容器应该算是最常用的容器之一了,它是序列式容器的一种,即元素可被排序。vector被称为动态数组,可以随着元素的加入,内部的大小自行扩充。可能你对vector的机制有所耳闻,比如每次扩充时,扩充当前容量的2倍等。接下来,我们就进入到它的源码来看看vector是如何实现的。我们将它分为四部分进行分析,vector的迭代器,vector的内存分配及构造,vector的内存控制以及一些常用

Move_now的博客 810

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

SGISTL源码探究-关联式容器:multimap

前言在本小节中我们将分析multimap的实现。它和map的最大的不同之处在于,map不允许重复的键值插入,而multimap允许重复的键值插入,对应到底层的实现,multimap调用的是insert_equal进行插入操作,而map调用的是insert_unique进行插入操作。 另外还有一个不同之处是multimap不支持下标运算,这个也很合理,因为可能有重复键,访问下标时可能就对应了多个值,

Move_now的博客 863

SGISTL源码探究-STL中的红黑树(上)

前言本小节将进入到SGISTL的红黑树部分。关于红黑树,是一种比较复杂的数据结构,但是并不是特别难。如果对红黑树不太了解,可以去网上查阅相关的资料,因为本文的主要目的是分析STL中的红黑树的源码,和普通的红黑树略有不同,还要复杂一些,需要有一定的基础。基本概念首先什么是二叉搜索树,二叉搜索树即符合任何一个节点的值一定大于其左子树的任何一个节点的值并且小于其右子树的任何一个节点的值(节点的值不允许重复

Move_now的博客 1806

SGISTL源码探究-stl_algo.h中的排序算法

前言在本小节中,我们将分析STL中算法组件的最后一部分:排序算法。排序算法分为内部排序和外部排序。而内部排序中常见的有八种排序算法:直接插入排序、希尔排序、简单选择排序、堆排序、冒泡排序、快速排序、归并排序、桶排序。在SGISTL实现的sort算法中,并不是简单的使用快速排序作为排序算法,而是交叉使用了插入排序、堆排序以及快速排序,并且做了一定的优化,并且只接受迭代器类型为RandomAccessI

Move_now的博客 938

SGISTL源码探究-配接器

前言关于配接器,之前在分析序列式容器时就已经分析过queue和stack,它们也是配接器的一种,通过使用其他容器的接口然后自己加以修饰,形成另外一种容器。除了应用在容器上之外,还有关于应用在仿函数上的配接器,就如我们上一小节分析仿函数时里面的例子一样。还有一种是应用在迭代器上的配接器,等下我们会进行分析。应用于容器的配接器关于这一部分,之前已经分析过queue和stack的实现了,这里就不做赘述了。

Move_now的博客 447

SGISTL源码探究-stl_numeric.h中的数值算法

前言上一小节中,我们对stl中的算法部分做了一个大致的说明。本小节我们将进入到其中关于数值算法的部分,都在stl_numeric.h文件中。废话不多说,直接看源码吧。stl_numericaccumulate注意该算法要求了迭代器的类型至少是InputIterator类型,如果是OutputIterator类型,肯定是不行的。 用于计算元素总和,init加上[first, last)范围内的元素之

Move_now的博客 682

SGISTL源码阅读二十 map关联式容器

SGISTL源码阅读二十 map关联式容器 前言 map是一种关联式容器,底层同样是红黑树实现的,所有的元素都会根据元素的键值自动被排序。map中所有的元素pair,pair将两个数据合成一个,将pair的第一个值视为键值,第二个值视为实值,非常符合key``````value的要求。 我们知道set保证了数据的唯一性,map也一样,在map中不允许两个元素拥有相同的键值。 深入源码 map的定义...

Lyn&Xx 470

SGISTL源码探究-pair的实现

前言本小节将对pair进行源码分析,它经常用于map的实现中,而我们下一节就会分析map的源码,所以有必要在这一小节中,先把pair分析了。 pair的作用就是将两个数据合成一个,而这两个数据可以是不同的类型,这就非常符合key-value这种键值对形式的存储了,接下来我们就进入到它的源码之中。pair的实现pair的实现代码很短,100行不到,但是对map的实现确实提供了非常大的便利。它提供的操

Move_now的博客 816

SGISTL源码探究-STL中的hashtable(上)

前言关于哈希表部分,哈希函数以及解决哈希冲突的方法都有很多种,在本文中不会详细去讨论哈希表的大量知识,而是以SGISTL实现的hashtable为主,所以如果对hashtable不太了解,建议先去网上查阅相关的资料。这里只给出基本的概念。了解哈希表原理基本概念哈希表(hashtable,也称散列表):根据key来访问元素的一种数据结构。它可能先经过哈希函数计算出key,然后通过key访问表中对应ke

Move_now的博客 1483

SGISTL源码阅读十三 list容器下

SGISTL源码阅读十三 list容器下 前言 我们将继续介绍list的相关操作 深入源码 remove remove的作用是删除指定值的节点 template &lt;class T, class Alloc&gt; void list&lt;T, Alloc&gt;::remove(const T&amp; value) { iterator first = begin(); ite...

Lyn&Xx 196

SGISTL源码阅读二十三 hashtable下

SGISTL源码阅读二十三 hashtable下 前言 之前介绍了hashtable的基本结构和它的构造方法,现在我们继续来学习它的迭代器和一些常用方法。 深入源码 hashtable的迭代器 //迭代器的声明 template &amp;amp;lt;class Value, class Key, class HashFcn, class ExtractKey, class EqualKe...

Lyn&Xx 274
上一篇: SGISTL源码探究-stl_algo.h中的排序算法
下一篇: SGISTL源码探究-配接器
UKey_
博客等级 码龄10年 258粉丝 186原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值