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

一个C++模板工厂的编译问题的解决。针对第三方库的构造函数以及追加了的对象构造函数。牵扯到重载、特化等

一窥模板的替换和匹配方式:偏特化的参数比泛化版本的还要多:判断是不是std::pair<,>。_stdpair模板参数太多-CSDN博客

简介

在一个项目里,调用了第三封的库,这个库里面有个类用的很多,而且其构造函数至少有6个,并且个人感觉还不够多。根据实际使用,还得增加一些。

需求

1、增加构造函数,比如除了下面的,还增加(ElementId,const std::wstring& modelName),以及FarElementId

2、希望能用通用的构造接口来生成对象,比如Create

3、希望能用指针对象(智能指针)

第三方库的6个构造函数

EditElementHandle (MSElementDescrCP descr, bool isUnmodified, DgnModelRefR modelRef);
EditElementHandle() {} 
EditElementHandle (MSElementDescrP descr, bool owned, bool isUnmodified, DgnModelRefP modelRef=NULL) ;
EditElementHandle (ElementRefP elRef, DgnModelRefP modelRef=NULL) : ElementHandle (elRef, modelRef) {}
EditElementHandle (MSElementCP el, DgnModelRefP modelRef) : ElementHandle (el, modelRef){}
EditElementHandle (ElementId id, DgnModelRefP modelRef) : ElementHandle (id, modelRef) {}

 定义智能指针

using EditElementHandlePtr = std::shared_ptr<DgnPlatform::EditElementHandle>;

定义工厂EEHFactory

struct EEhFactory
{template <typename ... Args>static HCHXKERNEL::EditElementHandlePtrCreate(Args&& ... args){return std::make_shared<DgnPlatform::EditElementHandle>(std::forward<Args>(args)...);}
};

可以这样使用:

ElementRefP elRef{ NULL };
DgnModelRefP modelRef{ NULL };
auto editElementHandlePtr1 = EEhFactory::Create(elRef, modelRef);

新需求

我想这样使用,怎么办:

DgnPlatform::ElementId eid0{ 0 };
std::wstring str{ L"" };
auto editElementHandlePtr2 = EEhFactory::Create(eid0, str);或者
auto editElementHandlePtr3 = EEhFactory::Create(eid0, std::wstring{ L"PipeDrawing" });或者
auto editElementHandlePtr3 = EEhFactory::Create(eid0,  L"PipeDrawing" );

问题:相当于增加了两个构造函数。这两个函数由我们自己实现

第一个尝试:非泛化版本

先加入普通静态函数,看什么效果,能否达到重载的目的:

struct EEhFactory
{template <typename ... Args>static HCHXKERNEL::EditElementHandlePtrCreate(Args&& ... args){return std::make_shared<DgnPlatform::EditElementHandle>(std::forward<Args>(args)...);}static HCHXKERNEL::EditElementHandlePtrCreate(ElementId eid, const std::wstring& modelName)
{DgnModelRefP modelRef = NULL;if (!MiscUtil::GetModelRefByName(&modelRef, modelName.c_str(), false, false))return NULL;return EEhFactoryXXX::Create(eid, modelRef);
}
};调用:
{DgnPlatform::ElementId eid0{ 0 };//, eid1{ 0 };DgnModelRefP modelRef = NULL;EEhFactoryXXX::Create(eid0, modelRef);
}

编译结果是:

 注意最后一句:

note: 参见对正在编译的函数 模板 实例化“std::shared_ptr<
Bentley::DgnPlatform::EditElementHandle
> 
EEhFactoryXXX::Create<Bentley::DgnPlatform::ElementId&,std::wstring&>
(Bentley::DgnPlatform::ElementId &,std::wstring &)”的引用

明明我们想要调用的是:

static HCHXKERNEL::EditElementHandlePtr  Create(ElementId eid, const std::wstring& modelName);

结果看起来,貌似编译器优先去泛型那边了:

template <typename ... Args>static std::shared_ptr<DgnPlatform::EditElementHandle>/*HCHXKERNEL::EditElementHandlePtr*/Create(Args&& ... args){return std::make_shared<DgnPlatform::EditElementHandle>(std::forward<Args>(args)...);}

这个第26行,就是泛型函数里的,压根没走到我们的普通函数那里。

 

 第二个尝试:泛化版本

改造一下,想法是推导的时候,

Param1st推导成ElementId,而Param2ndst推导成std::wstring:

struct  EEhFactoryXXX
{template <typename ... Args>static std::shared_ptr<DgnPlatform::EditElementHandle>/*HCHXKERNEL::EditElementHandlePtr*/Create(Args&& ... args){return std::make_shared<DgnPlatform::EditElementHandle>(std::forward<Args>(args)...);}template<typename T>struct IsFarElementID : std::false_type{};template<>struct IsFarElementID<DgnPlatform::DgnHistory::FarElementID> : std::true_type{};template<typename T>struct IsElementId : std::false_type{};template<>struct IsElementId<DgnPlatform::ElementId> : std::true_type{};template<typename T>struct IsWstring : std::false_type{};template<>struct IsWstring<std::wstring> : std::true_type{};template <typename Param1st, typename Param2ndst,typename std::enable_if<IsElementId<Param1st>::value &&IsWstring<Param2ndst>::value, int>::type = 0>static HCHXKERNEL::EditElementHandlePtr Create(Param1st eid,const Param2ndst& modelName){DgnModelRefP modelRef = NULL;if (!MiscUtil::GetModelRefByName(&modelRef, modelName.c_str(), false, false))return NULL;//using eid_decayType = typename std::decay<Param1st>::type;//typename std::decay<Param1st>::type a;//TypeDisplayer<decltype(a)> aType;//return NULL;return EEhFactoryXXX::Create(eid, modelRef);}
};调用:
{DgnPlatform::ElementId eid0{ 0 };//, eid1{ 0 };std::wstring str{ L"" };auto editElementHandlePtr2 = EEhFactoryXXX::Create(eid0, str);
}

但是呢,编译结果让人大吃一惊,出现的编译提示和之前一模一样,说明压根还是没走到我们新的泛型函数里来。

这次终于引起我的注意了

Param1st推导成Bentley::DgnPlatform::ElementId&?而Param2ndst推导成std::wstring &?

至于我期望的Elementid,和const std::wstring&,压根不挨着?const跑哪去了,压根没搭理我给出的定义?

而且还是走的原来的变参的模板定义。

Bentley::DgnPlatform::EditElementHandle
> 
EEhFactoryXXX::Create<Bentley::DgnPlatform::ElementId&,std::wstring&>
(Bentley::DgnPlatform::ElementId &,std::wstring &)”的引用

果然泛型这玩意,水太深了。

分析函数重载

睡觉之前琢磨了一下,感觉有头绪了

首先,类EEHFactory里的两个Create函数,都是static的泛型成员变量。一个是最泛化的版本,另一个是特化的版本。

这貌似牵扯到函数重载的问题?

但看看这个:函数模板之间不能重载,把类型推导放到形参里就可以了_template 函数无法重载-CSDN博客

是不是要分两种情况,是不是存在最泛化的版本。

存在最泛化的版本时

而且当前这个泛化的版本,是属于变参的,什么类型都能接受的那种。

编译器扫描到存在一个这样的泛化版本,先用它解析了一下参数类型。由于它是引用类型(Args&& ... args),左值的变量就推导出了左值引用,

{DgnPlatform::ElementId eid0{ 0 };std::wstring str{ L"" };auto editElementHandlePtr2 = EEhFactoryXXX::Create(eid0, str);
eid0和str都是左值变量,最后推到出来的类型就是左值引用:ElementId&和std::wstring&
}
auto editElementHandlePtr2 = 
EEhFactoryXXX::Create(eid0, std::wstring{L"PipeDrawing"});
的推导结果就是ElementId&,和std::wstring&&

好了,这个泛化版本先把类型给推导出来了,基调给定下来了,那就是ElementId&和std::wstring&。这个时候,它发现另一个Create函数,貌似可以重载,但得先检查一下,参数是否匹配。 

它发现,此Create的参数是:Param1st eid和const Param2ndst& modelName

从形式上看,就不符合。

所以,最后还是走最泛化的版本。

template <typename Param1st, typename Param2ndst,typename std::enable_if<IsElementId<Param1st>::value &&IsWstring<Param2ndst>::value, int>::type = 0>static HCHXKERNEL::EditElementHandlePtr Create(Param1st eid,const Param2ndst& modelName){DgnModelRefP modelRef = NULL;if (!MiscUtil::GetModelRefByName(&modelRef, modelName.c_str(), false, false))return NULL;return EEhFactoryXXX::Create(eid, modelRef);}

那我就让你如意,重新定义一下:

把Param1st eid和const Param2ndst& modelName改成:

Param1st& eid和Param2ndst& modelName。

就没事了。

struct  EEhFactoryXXX
{template <typename ... Args>static std::shared_ptr<DgnPlatform::EditElementHandle>/*HCHXKERNEL::EditElementHandlePtr*/Create(Args&& ... args){return std::make_shared<DgnPlatform::EditElementHandle>(std::forward<Args>(args)...);}template<typename T>struct IsFarElementID : std::false_type{};template<>struct IsFarElementID<DgnPlatform::DgnHistory::FarElementID> : std::true_type{};template<typename T>struct IsElementId : std::false_type{};template<>struct IsElementId<DgnPlatform::ElementId> : std::true_type{};template<typename T>struct IsWstring : std::false_type{};template<>struct IsWstring<std::wstring> : std::true_type{};template <typename Param1st, typename Param2ndst,typename std::enable_if<IsElementId<Param1st>::value &&IsWstring<Param2ndst>::value, int>::type = 0>static HCHXKERNEL::EditElementHandlePtr Create(Param1st& eid,Param2ndst& modelName){DgnModelRefP modelRef = NULL;if (!MiscUtil::GetModelRefByName(&modelRef, modelName.c_str(), false, false))return NULL;return EEhFactoryXXX::Create(eid, modelRef);}
};调用:
{DgnPlatform::ElementId eid0{ 0 };//, eid1{ 0 };std::wstring str{ L"" };auto editElementHandlePtr2 = EEhFactoryXXX::Create(eid0, str);
}

下面这个例子,帮助理解,但这是个类的例子,函数可能有所不同,但仅仅是帮助理解。

A的泛化版本根本没有实现,但它是不能缺少的,否则就编译报错。

第二个A是个偏特化版本。(还是特化?)

enable_if和类的偏特化-CSDN博客

#include <iostream>
template<class T, class Enabled=void >
class A;template<class T>
class A<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
public:A() { std::cout << "partial specialization\r\n";}
}; // specialization for floating point typesint main() {A<double> a;
}

不存在最泛化版本时

编译器别无选择。可以编译成功。

但如果是类,必须要有最泛化的版本。

struct  EEhFactoryXXX
{///@code{.unparsed}///此函数的功能:///  创建EditElementHandle的指针对象///  最泛化的版本///@endcode ///@return   true:成功 false:失败///@author Simon.Zou @date 2024/02/20//template <typename ... Args>//static std::shared_ptr<DgnPlatform::EditElementHandle>/*HCHXKERNEL::EditElementHandlePtr*///    Create(Args&& ... args)//{//    return std::make_shared<DgnPlatform::EditElementHandle>(std::forward<Args>(args)...);//}template<typename T>struct IsFarElementID : std::false_type{};template<>struct IsFarElementID<DgnPlatform::DgnHistory::FarElementID> : std::true_type{};template<typename T>struct IsElementId : std::false_type{};template<>struct IsElementId<DgnPlatform::ElementId> : std::true_type{};template<typename T>struct IsWstring : std::false_type{};template<>struct IsWstring<std::wstring> : std::true_type{};template <typename Param1st, typename Param2ndst,typename std::enable_if<IsElementId<Param1st>::value &&IsWstring<Param2ndst>::value, int>::type = 0>static HCHXKERNEL::EditElementHandlePtr Create(Param1st& eid,Param2ndst& modelName){DgnModelRefP modelRef = NULL;if (!MiscUtil::GetModelRefByName(&modelRef, modelName.c_str(), false, false))return NULL;return NULL; //return EEhFactoryXXX::Create(eid, modelRef); 
//暂时切换成return NULL。因为没有函数接收ElementId和DgnModelRefp}
// 
//     template <
//         typename Param1st, typename Param2ndst,
//         typename std::enable_if<
//         IsElementId<Param1st>::value &&
//         IsWstring<Param2ndst>::value
//         , int>::type = 0
//     >
//         static HCHXKERNEL::EditElementHandlePtr Create(
//             Param1st& eid,
//             Param2ndst&& modelName
//         )
//     {
//         return EEhFactoryXXX::Create(eid, modelName);
//     }};测试:
DgnPlatform::ElementId eid0{ 0 };//, eid1{ 0 };
std::wstring str{ L"" };
auto editElementHandlePtr2 = EEhFactoryXXX::Create(eid0, str);

相关文章:

一个C++模板工厂的编译问题的解决。针对第三方库的构造函数以及追加了的对象构造函数。牵扯到重载、特化等

一窥模板的替换和匹配方式&#xff1a;偏特化的参数比泛化版本的还要多&#xff1a;判断是不是std::pair&#xff1c;,&#xff1e;。_stdpair模板参数太多-CSDN博客 简介 在一个项目里&#xff0c;调用了第三封的库&#xff0c;这个库里面有个类用的很多&#xff0c;而且其构…...

《昇思 25 天学习打卡营第 20 天 | Pix2Pix实现图像转换 》

《昇思 25 天学习打卡营第 20 天 | Pix2Pix实现图像转换 》 活动地址&#xff1a;https://xihe.mindspore.cn/events/mindspore-training-camp 签名&#xff1a;Sam9029 Pix2Pix模型概述 Pix2Pix是一种基于条件生成对抗网络&#xff08;cGAN&#xff09;的图像转换模型&#x…...

关于c#的简单应用三题

#region 输入一个正整数&#xff0c;求1~这个数的阶乘 public static void Factorial(int a) { int result 1; for (int i 1; i < a; i) { result result * i; } Console.WriteLine(result); } #endregion #region 一个游戏&#…...

(十三)Spring教程——依赖注入之工厂方法注入

1.工厂方法注入 工厂方法是在应用中被经常使用的设计模式&#xff0c;它也是控制反转和单例设计思想的主要实现方法。由于Spring IoC容器以框架的方式提供工厂方法的功能&#xff0c;并以透明的方式开放给开发者&#xff0c;所以很少需要手工编写基于工厂方法的类。正是因为工厂…...

Redission中的Lua脚本写法、理解

对于Redission看门狗机制中的为了保证原子性的Lua脚本的写法规则是什么样的呢 &#xff1f; 对于源码中的Lua脚本又是什么意思&#xff1f; 我们一起来看一下 首先&#xff0c;我们先基本的熟悉一下lua脚本的逻辑 在Lua脚本中&#xff0c;if (…) then … end 语句的执行过程…...

视频共享融合赋能平台LntonCVS视频监控管理平台视频云解决方案

LntonCVS是基于国家标准GB28181协议开发的视频监控与云服务平台&#xff0c;支持多设备同时接入。该平台能够处理和分发多种视频流格式&#xff0c;包括RTSP、RTMP、FLV、HLS和WebRTC。主要功能包括视频直播监控、云端录像与存储、检索回放、智能告警、语音对讲和平台级联&…...

GraphRAG + GPT-4o mini 低成本构建 AI 图谱知识库

更好的效果&#xff0c;更低的价格&#xff0c;听起来是不是像梦呓&#xff1f; 限制 首先&#xff0c;让我们来介绍一个词&#xff1a;RAG。 简单来说&#xff0c;RAG&#xff08;Retrieval-Augmented Generation&#xff0c;检索增强生成&#xff09; 的工作原理是将大型文档…...

全国区块链职业技能大赛第十套区块链产品需求分析与方案设计

任务1-1:区块链产品需求分析与方案设计 养老保险平台中涉及到参保人、社保局、公安局、工作单位等参与方,他们需要在区块链养老保险平台中完成账户注册、身份上链、社保代缴、信息核查等多种业务活动。通过对业务活动的功能分析,可以更好的服务系统的开发流程。基于养老保险…...

分布式Apollo配置中心搭建实战

文章目录 环境要求第一步、软件下载第二步、创建数据库参考文档 最近新项目启动&#xff0c;采用Apollo作为分布式的配置中心&#xff0c;在本地搭建huanj 实现原理图如下所示。 环境要求 Java版本要求&#xff1a;JDK1.8 MySql版本要求&#xff1a;5.6.5 Apollo版本要求&…...

Android monkey命令和monkey脚本详解

Monkey命令 monkey 是 Android 平台上一个非常有用的工具&#xff0c;它可以帮助开发者在设备上生成随机的用户事件流&#xff0c;如按键输入、触摸屏手势等&#xff0c;以此来测试应用的稳定性。这对于发现应用中的崩溃、异常和性能问题特别有用。 基本语法 adb shell monk…...

vue 实现对图片的某个区域点选, 并在该区域上方显示该部分内容

目录 1、通义灵码实现&#xff1a; 2、csdn的C知道&#xff1a; 3、百度comate&#xff1a; 1、通义灵码实现&#xff1a; 在 Vue 中实现对图片某个区域的点选并显示该区域属于哪一部分&#xff0c;通常涉及到几个关键步骤&#xff1a; 图片区域划分&#xff1a; 首先&#…...

配置文件格式 INI 快速上手

文章目录 1.简介2.语法节键值对注释大小写空白行数据类型字符串 (String)整数 (Integer)浮点数 (Float)布尔值 (Boolean)列表 (List) 3.示例4.解析参考文献 1.简介 INI 的全称是 Initialization&#xff0c;即为初始化文件&#xff0c;最早是 Windows 系统配置文件所采用的格式…...

基于WebGoat平台的SQL注入攻击

目录 引言 一、安装好JAVA 二、下载并运行WebGoat 三、注册并登录WebGoat 四、模拟攻击 1. 第九题 2. 第十题 3. 第十一题 4. 第十二题 5. 第十三题 五、思考体会 1. 举例说明SQL 注入攻击发生的原因。 2. 从信息的CIA 三要素&#xff08;机密性、完整性、可用性&…...

SpringMvc有几个上下文

你好&#xff0c;我是柳岸花明。 SpringMVC作为Spring框架的重要组成部分&#xff0c;其启动流程和父子容器机制是理解整个框架运行机制的关键。本文将通过一系列详细的流程图&#xff0c;深入剖析SpringMVC的启动原理与父子容器的源码结构。 SpringMVC 父子容器 父容器的创建 …...

k8s部署rabbitmq集群

1 部署集群 1.1 安装 # 创建一个中间件的命名空间 kubectl create namespace middleware # 创建ConfigMap,包含RabbitMQ的配置文件内容 kubectl apply -f rabbitmq-configmap.yaml # 配置用于存储RabbitMQ数据的PersistentVolume&#xff08;PV&#xff09;和PersistentVolum…...

Python利用包pypinyin汉字转拼音(处理多音字)

一、汉字转拼音 在python中将汉字的拼音输出可以采用pypinyin包&#xff0c;一下是简单的demo示例&#xff1a; 默认调用pinyin方法转换时时默认时带声调的&#xff0c;不带声调需要添加“styleStyle.NORMAL”参数。 from pypinyin import pinyin, Styledef pinyin_transfer…...

推荐系统三十六式学习笔记:工程篇.常见架构24|典型的信息流架构是什么样的

目录 整体框架数据模型1.内容即Activity2.关系即连接 动态发布信息流排序数据管道总结 从今天起&#xff0c;我们不再单独介绍推荐算法的原理&#xff0c;而是开始进入一个新的模块-工程篇。 在工程实践的部分中&#xff0c;我首先介绍的内容是当今最热门的信息流架构。 信息…...

解决QEMU无法从非0x80000000处开始执行

解决QEMU无法从非0x80000000处开始执行 1 背景介绍2 问题描述3 原因分析4 解决办法5 踩坑回忆5.1 坑1 - 怀疑设备树有问题5.2 坑2 - 怀疑QEMU中内存未写入成功5.3 QEMU地址空间分析过程 1 背景介绍 在使用NEMU与QEMU做DiffTest的场景下&#xff0c;运行的固件为《RISC-V体系结…...

AI在候选人评估中的作用:精准筛选与HR决策的助力

一、引言 随着科技的迅猛发展&#xff0c;人工智能&#xff08;AI&#xff09;技术已逐渐渗透到各个行业和领域&#xff0c;人力资源管理&#xff08;HRM&#xff09;亦不例外。在候选人评估的环节中&#xff0c;AI技术以其高效、精准的特性&#xff0c;正在逐步改变着传统的招…...

自动化测试的艺术:Xcode中GUI测试的全面指南

自动化测试的艺术&#xff1a;Xcode中GUI测试的全面指南 在软件开发过程中&#xff0c;图形用户界面&#xff08;GUI&#xff09;测试是确保应用质量和用户体验的关键环节。Xcode&#xff0c;作为苹果的官方集成开发环境&#xff08;IDE&#xff09;&#xff0c;提供了一套强大…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

AtCoder 第409​场初级竞赛 A~E题解

A Conflict 【题目链接】 原题链接&#xff1a;A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串&#xff0c;只有在同时为 o 时输出 Yes 并结束程序&#xff0c;否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

uniapp中使用aixos 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式

今天是关于AI如何在教学中增强学生的学习体验&#xff0c;我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育&#xff0c;这并非炒作&#xff0c;而是已经发生的巨大变革。教育机构和教育者不能忽视它&#xff0c;试图简单地禁止学生使…...

Kafka入门-生产者

生产者 生产者发送流程&#xff1a; 延迟时间为0ms时&#xff0c;也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于&#xff1a;异步发送不需要等待结果&#xff0c;同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

华为OD机考-机房布局

import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...

第7篇:中间件全链路监控与 SQL 性能分析实践

7.1 章节导读 在构建数据库中间件的过程中&#xff0c;可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中&#xff0c;必须做到&#xff1a; &#x1f50d; 追踪每一条 SQL 的生命周期&#xff08;从入口到数据库执行&#xff09;&#…...

Matlab实现任意伪彩色图像可视化显示

Matlab实现任意伪彩色图像可视化显示 1、灰度原始图像2、RGB彩色原始图像 在科研研究中&#xff0c;如何展示好看的实验结果图像非常重要&#xff01;&#xff01;&#xff01; 1、灰度原始图像 灰度图像每个像素点只有一个数值&#xff0c;代表该点的​​亮度&#xff08;或…...

从零手写Java版本的LSM Tree (一):LSM Tree 概述

&#x1f525; 推荐一个高质量的Java LSM Tree开源项目&#xff01; https://github.com/brianxiadong/java-lsm-tree java-lsm-tree 是一个从零实现的Log-Structured Merge Tree&#xff0c;专为高并发写入场景设计。 核心亮点&#xff1a; ⚡ 极致性能&#xff1a;写入速度超…...