当前位置: 首页 > article >正文

Re:思考·重建·记录 现代C++ C++11篇 (三) 深度解构:可变参数模板、类功能演进与 STL 的新版图

◆ 博主名称 晓此方-CSDN博客大家好欢迎来到晓此方的博客。⭐️现代C系列个人专栏 插曲现代C⭐️Re系列专栏我们思考 (Rethink) · 我们重建 (Rebuild) · 我们记录 (Record)文章目录概要序論一模板中的模板可变参数模板1.1从概念开始——什么是可变参数与参数包1.1.1从C库中的printf引入1.1.2模板的可变参数Tips新操作符追加sizeof...1.2简化代码的利器——可变参数模板该怎么用1.2.1 递归函数方式展开参数包包扩展1.2.2包扩展的终止函数的设计为何重要1.2.3强化对参数包的理解——另外一种调用场景分析1.2.4总结——可变参数模板就是模板中的模板1.3库里面的可变参数模板——emplace系列接口1.3.1C11新增emplace系列接口1.3.1.1这里的“更高效”到底是怎么回事1.3.1.2push_back与emplace_back调用上的异同1.4在模拟list中看emplace_back的运行过程二新的类功能2.1默认的移动构造和移动赋值2.2成员变量声明时给缺省值2.3 defult和delete2.4 final与override三STL中一些变化概要序論这里是此方好久不见。本专栏是【主题曲C程序设计】专栏的补充篇【插曲现代C】。本系列将优先深度解析C11标准力求内容详实无微不至。C14~C20的进阶内容将在后续间隔一段时间后连载。本期将重点讲解可变参数模板、C11新的类功能以及STL中的新变化.好的让我们现在开始吧。C模板相关内容往期回顾本篇某种意义上也算是模版的现代进阶篇了doge模板初阶Re从零开始的 C 入門篇十二过渡章节模板初阶与STL简单介绍模板进阶Re从零开始的 C 进阶篇一超全的模板进阶详解非类型模板参数、模板特化、与模板的分离编译一模板中的模板可变参数模板1.1从概念开始——什么是可变参数与参数包1.1.1从C库中的printf引入在梦开始的地方C语言时期我们接触过一个函数printf他就是一个可变参数的函数。可变参数意味着我们可以传递任意多个参数给函数并完成相关操作。但是这个函数的可变参数的底层是通过一个数组来存储参数并打印的。我们接下来学习的模板的可变参数与此又有不同。1.1.2模板的可变参数C11支持可变参数模板也就是说支持可变数量参数的函数模板和类模板可变数目的参数被称为参数包存在两种参数包模板参数包表示零或多个模板参数函数参数包表示零或多个函数参数。templateclass...ArgsvoidFunc(Args...args){}templateclass...ArgsvoidFunc(Args...args){}templateclass...ArgsvoidFunc(Args...args){}我们用省略号来指出一个模板参数或函数参数表示一个包在模板参数列表中class… 或 typename… 指出接下来的参数表示零或多个类型列表在函数参数列表中类型名后面跟 … 指出接下来表示零或多个形参对象列表函数参数包可以用左值引用或右值引用表示跟前面普通模板一样每个参数实例化时遵循引用折叠规则。可变参数模板的原理跟模板类似本质还是去实例化对应类型和个数的多个函数。Tips新操作符追加“sizeof…”sizeof… 是 C11 引入的一个预处理器/编译时操作符返回变长参数模板中**“参数包”所包含的参数个数。**#includeiostream#includestringusingnamespacestd;templateclass...Argsvoidprint(Args...args){coutsizeof...(args)endl;}intmain(){inti0;intj1;doublek2;charl3;string m123456;print(i);print(i,j);print(i,j,k,l,m,1,9,546);return0;}如上图我们写了一个可变模板参数右值引用版本的函数print我们可以传递任意类型任意数量不分左右值的参数给函数print。函数内部的sizeof…操作符表达式语句打印结果分别是128.1.2简化代码的利器——可变参数模板该怎么用虽然我们通过 sizeof… 拿到了参数包的数量但仅仅知道“有多少个”是不够的。在实际开发中我们最迫切的需求是如何取出参数包里的每一个参数。与普通数组不同你不能通过 args[i] 这种下标方式来访问参数包。在 C11 中展开参数包主流的方式是编译递归法。1.2.1 递归函数方式展开参数包包扩展这是最经典、最符合“模板直觉”的方法。它的核心思想是将参数包拆解为第一个参数Head 剩余参数包Tail。通过不断递归调用自身一层层“剥开”参数包。#includeiostream#includestringusingnamespacestd;// 1. 递归终止函数,当参数包 args... 为空时会匹配这个无参的 ShowListvoidShowList(){coutendl;}// 2. 展开函数递归推导,每次调用都会将参数包的第一个参数赋给 x剩下的 N-1 个参数包给 args...templateclassT,class...ArgsvoidShowList(T x,Args...args){coutx ;ShowList(args...);}// 3. 可变参数模板入口templateclass...ArgsvoidPrint(Args...args){ShowList(args...);}intmain(){Print(1,string(xxxxx),2.2);return0;}就代码进行原理分析匹配 Print(int, string, double)它内部调用 ShowList(1, “xxxxx”, 2.2)。匹配 ShowList(T x, Args… args)此时 x 是 1剩下的包是 (“xxxxx”, 2.2)。编译器实例化出一个处理 int 的函数。递归调用 ShowList(“xxxxx”, 2.2)此时 x 是 “xxxxx”剩下的包是 (2.2)。编译器实例化出一个处理 string 的函数。递归调用 ShowList(2.2)此时 x 是 2.2剩下的包为空。编译器实例化出一个处理 double 的函数。递归调用 ShowList()匹配到那个最简单的无参终止函数递归结束。1.2.2包扩展的终止函数的设计为何重要有人看到我上面的这段代码可能会问了”哎呀此方啊递归调用在函数内部写一个递归终止条件不就好了怎么要这么麻烦“不对这和以前的递归还不一样上面模板的递归实际上是一个编译时递归实例化的过程。如下图在编译时通过不断的递归生成对应参数个数的函数模板。再通过参数类型将这些模板实例化成对应参数类型的函数。在运行时沿着如下的调用顺序依次调用这些已经被实例化出来的函数。于是回答上面的问题终止函数void ShowList(){ cout endl;}就非常必要因为如果没有它作为递归的出口编译器在面对“剥离”后变为空的参数包时会由于找不到匹配的函数原型而直接罢工报错。1.2.3强化对参数包的理解——另外一种调用场景分析如下代码Arguments(GetArg(args)…);要传递一个参数包给Arguments函数。这个调用Arguments函数参数包的每一个参数都是GetArg函数的调用返回值同时GetArg函数每次只能接收一个参数也就是说GetArg函数被调用了sizeof…(args)次每一次按顺序接收一个来自参数包… args的参数。在这个过程中编译器底层实际上也是帮助你生成了很多的函数并调用的就像这样Arguments(GetArg(1), GetArg(2), GetArg(3)…);templateclassTintGetArg(constTx){coutx ;return0;}templateclass...ArgsvoidArguments(Args...args){}templateclass...ArgsvoidPrint(Args...args){// 注意GetArg必须返回或者到的对象这样才能组成参数包给Arguments.Arguments(GetArg(args)...);}1.2.4总结——可变参数模板就是模板中的模板综上可变参数模板本质上是一个更加灵活的模板。如果不支持可变模板参数那么我也需要写五个这样的函数。就是说这个就是一个模板的模板。如下图对上文的包展开进行总结。需要注意的是这里的可变参数模板在编译器的实例化有两步编译器可能会合二为一成一步。实际上通过类似于这样的递归生成函数不能说是“递归调用”而应该是函数重载只能说编译时是递归编译生成运行时本质是函数重载我还想讲两句可能有小伙伴说C这种设计太挫了为什么参数包展开不设计成“底层用一个容器来存放参数遍历展开”呢实际上不是不想而是不能C17之前都不允许往一共容器里面放不同类型的参数。1.3库里面的可变参数模板——emplace系列接口1.3.1C11新增emplace系列接口templateclass...Argsvoidemplace_back(Args...args);templateclass...Argsiteratoremplace(const_iterator position,Args...args);C11以后STL容器新增了emplace系列的接口emplace系列的接口均为模板可变参数功能上兼容push和insert系列但是emplace还支持新玩法假设容器为container T emplace还支持直接插入构造T对象的参数这样有些场景会更高效一些可以直接在容器空间上构造T对象。emplace_back总体而言是更高效推荐以后使用emplace系列替代insert和push系列1.3.1.1这里的“更高效”到底是怎么回事很多小伙伴看完上文说emplace_back 比 push_back 快但总觉得云里雾里的。咱们直接看图里的核心逻辑其实就是“少了一次搬运”。push_back看图中左上角push_back 的参数类型是固定的 value_type这里咱们显式实例化成了 string。当你传一个字符串字面量 “1111111111” 进去时编译器发现类型不匹配一个是 const char*一个是 string。于是编译器会默默地先用这个字面量构造一个 string 临时对象。然后push_back 再把这个临时对象拷贝构造或移动构造到 list 的新节点里。代价 产生了一个临时对象并多了一次构造调用。emplace_back再看左下角emplace_back 是个可变参数模板。它的参数类型是在调用那一刻才确定的。当你传 “1111111111” 时它直接把这个 const char* 类型的参数原封不动地“传递”给了 list node 的构造函数。最终在容器申请好的那块内存空间上直接原地调用构造函数生成 string。代价 没有中间商赚差价直接在目的地合体.1.3.1.2push_back与emplace_back调用上的异同1.和push_back一样左值调用构造右值调用拷贝构造。intmain(){listpairbit::string,intlt1;// 跟push_back一样// 构造pair 拷贝/移动构造pair到list的节点中pairbit::string,intkv(苹果,1);lt1.emplace_back(kv);cout**********************endl;// 跟push_back一样lt1.emplace_back(move(kv));cout**********************endl;return0;}上面代码的测试结果string(char*str)-构造string(conststrings)--拷贝构造**************************string(strings)--移动构造**************************2.和push_back不同传参加不加{}有规矩。push_back的参数个数和类型已经被固定了必须传递一个{}扩起来的值。emplace_back不能传递一个{}括起来的值因为 { “苹果”, 1 } 这种初始化列表braced-init-list本身没有确定的类型它无法直接推导出模板参数 Args。——是的emplace_back不支持列表构造intmain(){listpairbit::string,intlt1;//这里达到的效果是push_back做不到的lt1.emplace_back(苹果,1);//lt1.push_back(苹果, 1); // ← 编译错误被注释或报错lt1.push_back({苹果,1});// 反而emplace不能这么写// lt1.emplace_back({ 苹果, 1 }); // ← 错误写法被划掉或注释lt1.emplace_back(苹果,1);lt1.push_back({苹果,1});// ← 正确使用初始化列表构造 pairreturn0;}1.4在模拟list中看emplace_back的运行过程我们模拟实现了list的emplace_back接口这里把参数包不段往下传递最终在结点的构造中直接去匹配容器存储的数据类型T的构造所以达到了前面说的emplace支持直接插入构造T对象的参数这样有些场景会更高效一些可以直接在容器空间上构造T对象。传递参数包过程中如果是 Args… args 的参数包要用完美转发参数包方式如下std::forward(args)… 否则编译时包扩展后右值引用变量表达式就变成了左值。// Test.cpp#includeList.h#includeiostreamusingnamespacestd;intmain(){bit::listpairstring,intlt1;lt1.emplace_back(苹果,1);return0;}//List.h#pragmaoncenamespacebit{templateclassTstructListNode{ListNodeT*_next;ListNodeT*_prev;T _data;ListNode(Tdata):_next(nullptr),_prev(nullptr),_data(move(data)){}templateclass...ArgsListNode(Args...args):_next(nullptr),_prev(nullptr),_data(std::forwardArgs(args)...){}};templateclassT,classRef,classPtrstructListIterator{typedefListNodeTNode;typedefListIteratorT,Ref,PtrSelf;Node*_node;ListIterator(Node*node):_node(node){}// itSelfoperator(){_node_node-_next;return*this;}Selfoperator--(){_node_node-_prev;return*this;}Refoperator*(){return_node-_data;}booloperator!(constSelfit){return_node!it._node;}};templateclassTclasslist{public:typedefListNodeTNode;typedefListIteratorT,T,T*iterator;typedefListIteratorT,constT,constT*const_iterator;iteratorbegin(){returniterator(_head-_next);}iteratorend(){returniterator(_head);}voidempty_init(){_headnewNode();_head-_next_head;_head-_prev_head;}list(){empty_init();}voidpush_back(constTx){insert(end(),x);}voidpush_back(Tx){insert(end(),move(x));}iteratorinsert(iterator pos,constTx){Node*curpos._node;Node*newnodenewNode(x);Node*prevcur-_prev;// prev newnode curprev-_nextnewnode;newnode-_prevprev;newnode-_nextcur;cur-_prevnewnode;returniterator(newnode);}iteratorinsert(iterator pos,Tx){Node*curpos._node;Node*newnodenewNode(move(x));Node*prevcur-_prev;// prev newnode curprev-_nextnewnode;newnode-_prevprev;newnode-_nextcur;cur-_prevnewnode;returniterator(newnode);}templateclass...Argsvoidemplace_back(Args...args){insert(end(),std::forwardArgs(args)...);}templateclass...Argsiteratorinsert(iterator pos,Args...args){Node*curpos._node;Node*newnodenewNode(std::forwardArgs(args)...);Node*prevcur-_prev;// prev newnode curprev-_nextnewnode;newnode-_prevprev;newnode-_nextcur;cur-_prevnewnode;returniterator(newnode);}private:Node*_head;};}二新的类功能2.1默认的移动构造和移动赋值原来C类中有6个默认成员函数,默认成员函数就是我们不写编译器会生成一个默认的。C11 新增了两个默认成员函数移动构造函数和移动赋值运算符重载。构造函数、析构函数、拷贝构造函数拷贝赋值重载、取地址重载、const 取地址重载如果你没有自己实现移动构造函数且没有实现析构函数、拷贝构造、拷贝赋值重载中的任意一个。委员会认为这三者是绑定在一起的你写了其中一者就会去写其他几者 那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数:对于内置类型成员会执行逐成员按字节拷贝(浅拷贝)。并没有“移动语义”中的夺取资源。自定义类型成员则需要看这个成员是否实现移动构造如果实现了就调用移动构造没有实现就调用拷贝构造。如果你没有自己实现移动赋值重载函数且没有实现析构函数、拷贝构造、拷贝赋值重载中的任意一个那么编译器会自动生成一个默认移动赋值。默认生成的移动赋值重载函数:对于内置类型成员会执行逐成员按字节拷贝。自定义类型成员则需要看这个成员是否实现移动赋值如果实现了就调用移动赋值没有实现就调用拷贝赋值。默认移动赋值跟上面移动构造完全类似如果你提供了移动构造或者移动赋值编译器不会自动提供拷贝构造和拷贝赋值。2.2成员变量声明时给缺省值成员变量声明时给缺省值是给初始化列表用的如果没有显示在初始化列表初始化就会在初始化列表用这个却绳子初始化这个我们在类和对象部分讲过了。精准投送在这篇文章的第3.5点讲得非常详细Re从零开始的 C 入門篇九类和对象·最终篇上缓冲区同步与流绑定、取地址运算符重载、const成员函数、初始化列表2.3 defult和deleteC11可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数但是因为一些原因这个函数没有默认生成。比如我们提供了拷贝构造就不会生成移动构造了那么我们可以使用 default 关键字显示指定移动构造生成。classMyClass{public:// 强制编译器生成默认构造函数MyClass()default;// 因为写了这个编译器原本不会自动生成 MyClass()MyClass(intx):_val(x){}private:int_val;};MyClass obj;// 有了 default这里才不会报错如果能想要限制某些默认函数的生成在C98中是该函数设置成 private并且只声明补丁已应为“只声明不定义”这样只要其他人想要调用就会报错。在C11中更简单只需在该函数声明加上 delete 即可该语法指示编译器不生成对应函数的默认版本称 delete 修饰的函数为删除函数。classNoCopy{public:NoCopy()default;// 禁止拷贝构造和赋值NoCopy(constNoCopy)delete;NoCopyoperator(constNoCopy)delete;};NoCopy a;// NoCopy b a; // 编译直接报错库里面的举例IO流不允许拷贝。2.4 final与override这个我们在继承和多态章节已经进行了详细讲过了精准投送这篇文章的第五点:Re从零开始的 C 进阶篇三彻底搞懂 C 多态虚函数、虚表与动态绑定的底层原理三STL中一些变化下图1圈起来的就是STL中的新容器但是实际最有用的是unordered_map 和 unordered_set。这两个我们前面已经进行了非常详细的讲解其他的大家了解一下即可。STL中容器的新接口也不少最重要的就是右值引用和移动语义相关的 push/insert/emplace 系列接口和移动构造和移动赋值还有 initializer_list 版本的构造等这些前面都讲过了还有一些无关痛痒的如 cbegin/cend 等需要时查文档即可。容器的范围 for 遍历这个在容器部分也讲过了。好了本期内容到此结束我是此方我们下期再见。バイバイ

相关文章:

Re:思考·重建·记录 现代C++ C++11篇 (三) 深度解构:可变参数模板、类功能演进与 STL 的新版图

◆ 博主名称: 晓此方-CSDN博客 大家好,欢迎来到晓此方的博客。 ⭐️现代C系列个人专栏: 插曲:现代C ⭐️Re系列专栏:我们思考 (Rethink) 我们重建 (Rebuild) 我们记录 (Record) 文章目录概要&序論一&#xff0c…...

STM32G4霍尔有感运行实战:从零配置到电流环闭环调试(附完整代码)

STM32G4霍尔传感器电机控制实战:从电流环配置到闭环调试全解析 霍尔传感器在无刷直流电机(BLDC)控制中扮演着关键角色,它通过检测转子位置为控制系统提供关键的反馈信息。STM32G4系列微控制器凭借其高性能定时器和丰富的外设资源&…...

PDS 2020.3 联合 ModelSim 仿真避坑指南:从编译库到解决 GRS_INST 报错的全流程

PDS 2020.3 联合 ModelSim 仿真实战避坑手册:从环境配置到疑难解析 在数字电路设计流程中,仿真验证环节往往决定着项目成败。当PangoDesign Suite 2020.3(简称PDS)遇上ModelSim这对黄金组合时,理论上应该实现无缝衔接的…...

深入WebRTC客户端架构:手把手解析基于libwebrtc.a与ZLMediaKit的C++推拉流核心模块设计

WebRTC客户端架构深度解析:从模块设计到实战优化 在实时音视频通信领域,WebRTC已经成为事实上的标准技术栈。不同于简单的API调用,一个工业级可用的WebRTC客户端需要精心设计的架构来应对复杂的网络环境和多样化的业务需求。本文将带您深入We…...

大营销平台 —— 抽奖前置规则过滤

一、前言上一期我们实现了权重配置的装配,这一期我们将实现抽奖业务的前置规则过滤,这里主要涉及了两个规则,第一个是黑名单(要求这些用户100积分只能抽到1积分),第二个是权重抽奖(在幸运值达到…...

Android 13手势导航卡顿?深入剖析Launcher3最近任务(Recents)的动画性能优化点

Android 13手势导航卡顿?深入剖析Launcher3最近任务(Recents)的动画性能优化点 在Android 13中,手势导航已经成为主流交互方式,但不少开发者反馈在Launcher3的最近任务(Recents)界面会出现动画卡…...

FRCRN语音增强工具实操手册:批量处理WAV文件的Shell脚本示例

FRCRN语音增强工具实操手册:批量处理WAV文件的Shell脚本示例 你是不是也遇到过这样的烦恼?手头有一堆录音文件,背景里混杂着键盘声、空调声、甚至窗外的车流声,想提取清晰的人声简直是一场耳朵的折磨。或者,你正在处理…...

海南大学交友平台开发实战 day10(后端向前端输出_前端读取数据全流程联调+日志调试落地)

海南大学交友平台开发实战 day10(后端向前端输出/前端读取数据全流程联调日志调试落地) 大家好,欢迎来到海南大学交友平台开发实战系列的第十天!在前九天的开发中,我们已完成登录注册、UI 布局、Flask 后端基础搭建、S…...

KosxPDF批量PDF盖章工具|支持骑缝章+电子章+多文件合并,高效智能文档签章解决方案

温馨提示:文末有联系方式功能亮点:全能PDF批量签章管理 KosxPDF电子文档批量骑缝章管理工具,专为高效处理PDF签章需求设计。 它不仅支持单文件或多文件批量加盖普通电子章,更可智能生成跨页连续骑缝章,确保文档完整性与…...

如何利用国内LLM对Obsidian的笔记进行分析

Win11 下用 Obsidian OpenCode 智谱 GLM 的安装与配置教程适用场景:不能方便走代理,但希望把 Obsidian 接到大模型,用于笔记整理、润色、总结与后续工具扩展。 本教程基于我们已经跑通的方案:Obsidian Agent Client OpenCode A…...

STL迭代器:核心概念与实战指南

迭代器基础概念迭代器是STL的核心组件之一,提供了一种统一的方式来访问容器中的元素。迭代器类似于指针,可以指向容器中的某个元素,并支持解引用、递增等操作。迭代器分为五种类型:输入迭代器、输出迭代器、前向迭代器、双向迭代器…...

CloudSaver 神器上手就会,一键搜全网资源 + 转存网盘!cpolar 内网穿透实验室第 731 个成功挑战

软件名称 CloudSaver(网盘资源整合 转存神器) 操作系统支持 支持群晖 NAS(全型号适配)、Windows/macOS(Docker 环境下)、Linux(Docker 部署),适配 PC 端 移动端&…...

【Claude Code 源码解析教程】第1章:Claude Code 项目介绍

本章将全面介绍 Claude Code 项目的产品定位、技术栈选型、项目代号含义以及核心功能特性,帮助读者建立对项目的整体认知。目录 1.1 产品定位与业务目标 1.1.1 产品定位 1.1.2 核心价值主张 1.1.3 业务目标 1.1.4 目标用户 全栈软件开发者 DevOps / SRE 工程…...

【读书笔记】《活着》

余华《活着》——解读整理一、如何理解《活着》的文学性质 很多读者会觉得《活着》“不够现实”——福贵的妻子家珍、父母等家人形象过于完美,情节过于戏剧性。要解开这个疑惑,首先需要纠正一个基本认知:《活着》是一部"现实主义底色的寓…...

学术是一场马拉松吗

最近录用一篇 EJOR,虽然是一件比较高兴的事,却没有那么的喜悦。因为根据我阅读多篇 EJOR 论文的经验,这篇投稿论文有 EJOR 的实力,即使被拒稿了,我会转投 COR 或者领域内其他不错的杂志,晚点发表而已。 目前…...

OriginPro与Python联用(Chapter 1)

Python在数据处理方面相较于Origin和Excel等工具具有比较显著的优势,特别是当流程重复或者数据量比较大的时候,但是Origin所见即所得的绘图方式往往更加容易上手一些,所以将二者结合起来使用可以同时使用他们的长处。这里我们主要介绍在外部使…...

AI前沿思想、AI理想、AI的妄言、AI极致观测文明

一、前言本文来自全世界的信息整理,本人对Ai内容进行记录和学习 ,如有异议和争论,请留言更正,不涉及现实相关事实。本文观点仅供参考。如有雷同,不回应。二、AI文明级变革观点1.旨在记录那些冲破常规的、甚至略显疯狂的…...

忙得上天入地的导师派师姐助我毕设之救我狗命笔记(二)

关于我的毕设,鄙人零基础小白年少无知狮子大开口,提笔落墨就是:1采用公开的SatSOT、VISO、OOTB等数据集进行程序调试;2对AQATrack、Stark、VideoX等模型进行比较分析谁曾想呢,宏图伟业卡在路径问题,AQATrac…...

Win10+VS2019配置vcpkg:从安装到项目集成的完整指南

1. 初识vcpkg:C开发者的效率神器 第一次接触vcpkg是在2018年接手一个跨平台C项目时,当时被各种第三方库的编译依赖折磨得够呛。vcpkg就像黑暗中的一束光,彻底改变了我的开发体验。简单来说,vcpkg是微软开源的C包管理工具&#xf…...

从零到项目发布:用VSCode和CMake管理你的第一个C++小游戏(Windows平台实战)

从零构建C控制台游戏:VSCodeCMakeGit全流程实战指南 在Windows平台上开发C项目,很多初学者会遇到环境配置复杂、构建工具不熟悉、代码管理混乱等问题。本文将带你用VSCodeCMakeGit这套现代开发工具链,从零开始构建一个完整的控制台猜数字游戏…...

监督学习(六):LightGBM实战优化技巧

1. LightGBM快速入门:为什么选择它? 第一次接触LightGBM是在处理一个电商用户行为预测项目时,当时数据集有300多万条记录,XGBoost跑一次要6小时,换成LightGBM后训练时间直接缩短到40分钟。这个经历让我彻底被它的效率征…...

技术总监拿了45万年终奖突然离职,我们以为是被别人挖走了,真相是总监发现自己管理的两个核心项目,被公司偷偷转移给空降的新领导

职场上最扯淡的事儿是啥?不是钱少事多,而是把你当驴使,还防着你。最近听了个事儿,特上头。一个技术总监,能力杠杠的,带着团队吭哧吭哧搞定了两个核心项目,老板一高兴,年终奖发了45万…...

RTKLIB源码深度解析:从编译调试到核心算法实现

1. RTKLIB概述与开发环境搭建 RTKLIB是全球导航卫星系统(GNSS)领域最著名的开源定位解算程序包,由日本东京海洋大学的高须知二博士开发。这个项目包含一个核心程序库和多个命令行/界面程序,代码规范、功能完善且扩展性强&#xff…...

海康摄像头字符叠加实战:SDK解码与数据流回调的深度对比

1. 海康摄像头字符叠加的两种实现方式 第一次接触海康摄像头开发时,我被字符叠加这个需求难住了整整一周。当时项目需要在监控画面上实时显示时间戳和车牌识别结果,试了好几种方案都不理想。后来才发现,海康官方SDK其实提供了两种完全不同的实…...

镜像视界提出3D Spatial Agent:AI正式进入空间时代——从“理解内容”到“计算空间”的范式跃迁

一、开篇:AI的下一个时代,不在模型,而在空间过去十年,人工智能行业迎来了以大模型为核心的爆发式增长浪潮,这一浪潮彻底重塑了机器与数据的交互方式。以OpenAI为代表的前沿机构,凭借突破性的语言模型技术&a…...

Python自动化抓取Keep运动数据:从入门到实战

1. 为什么需要自动化抓取Keep运动数据 作为一个健身爱好者,我每天都会用Keep记录自己的运动数据。但时间久了发现一个问题:这些宝贵的数据都散落在App里,想做个长期分析特别麻烦。每次都要手动截图、复制粘贴,效率低不说&#xff…...

解密 transforms.Normalize():PyTorch 图像标准化的数学原理与实战技巧

1. transforms.Normalize()的数学本质 当你第一次看到PyTorch代码里出现transforms.Normalize(mean[0.5, 0.5, 0.5], std[0.5, 0.5, 0.5])时,可能会疑惑这行简单的代码背后到底发生了什么。让我们拆解这个看似简单的操作背后的数学原理。 标准化公式的完整推导过程是…...

[最新战况]融入止盈止损模块!收益曲线更平稳!ETF三因子轮动实盘跟踪!股票量化分析工具QTYX-V3.4.5

前言我们的股票量化系统QTYX在实战中不断迭代升级!!!分享QTYX系统目的是提供给大家一个搭建量化系统的模版,帮助大家搭建属于自己的系统。因此我们提供源码,可以根据自己的风格二次开发。 关于QTYX的使用攻略可以查看链接:QTYX使用攻略QTYX一…...

告别云端排队:6GB显存笔记本实战FramePack,解锁个人图生视频创作自由

1. 为什么你需要FramePack? 每次看到别人用AI生成酷炫的视频,你是不是也心痒痒?但打开云端服务一看:排队2小时,生成5分钟,还要担心隐私泄露。更别提那些按秒计费的专业平台,钱包真的伤不起。这就…...

Pixel Couplet Gen部署案例:高校计算机系毕业设计展示平台

Pixel Couplet Gen部署案例:高校计算机系毕业设计展示平台 1. 项目背景与价值 在高校计算机专业的毕业设计中,如何将前沿AI技术与创意设计相结合,打造出既有技术深度又具备视觉冲击力的作品,一直是师生们关注的焦点。Pixel Coup…...