一个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::EditElementHandlePtr
        Create(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::EditElementHandlePtr
        Create(Args&& ... args)
    {
        return std::make_shared<DgnPlatform::EditElementHandle>(std::forward<Args>(args)...);
    }

static HCHXKERNEL::EditElementHandlePtr
        Create(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 types
 
int 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);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/869984.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Godot入门 03世界构建1.0版

在game场景&#xff0c;删除StaticBody2D节点&#xff0c;添加TileMap节点 添加TileSet图块集 添加TileSet源 拖动图片到图块&#xff0c;自动创建图块 使用橡皮擦擦除。取消橡皮擦后按住Shift创建大型图块。 进入选择模式&#xff0c;TileMap选择绘制&#xff0c;选中图块后在…

zookeeper开启SASL权限认证

目录 一、SASL介绍 二、使用 SASL 进行身份验证 2.1 服务器到服务器的身份验证 2.2 客户端到服务器身份验证 三、验证功能 一、SASL介绍 默认情况下&#xff0c;ZooKeeper 不使用任何形式的身份验证并允许匿名连接。但是&#xff0c;它支持 Java 身份验证与授权服务(JAAS)…

单元测试的最佳实践

整体架构 合适的架构可以提升可测试性。比如菱形对称架构的模块化和解耦特性使得系统各个部分可以独立进行单元测试。这不仅提高了测试的效率&#xff0c;还能够减少测试的依赖性&#xff0c;提高测试准确性。 代码设计 代码设计和可测试性有密切关联。强烈建议一个方法的代码行…

使用法国云手机进行面向法国的社媒营销

在当今数字化和全球化的时代&#xff0c;社交媒体已经成为企业营销和拓展市场的重要工具。对于想进入法国市场的企业来说&#xff0c;如何在海外社媒营销中脱颖而出、抓住更多的市场份额&#xff0c;成为了一个关键问题。法国云手机正为企业提供全新的营销工具&#xff0c;助力…

Flink源码学习资料

Flink系列文档脑图 由于源码分析系列文档较多&#xff0c;本人绘制了Flink文档脑图。和下面的文档目录对应。各位读者可以选择自己感兴趣的模块阅读并参与讨论。 此脑图不定期更新中…… 文章目录 以下是本人Flink 源码分析系列文档目录&#xff0c;欢迎大家查阅和参与讨论。…

iPhone 17系列取消17 Plus版本?新一代苹果手机迎来新变革

随着科技的飞速发展&#xff0c;苹果公司再次准备刷新我们的期待&#xff0c;即将推出的iPhone 17系列携带着一系列令人兴奋的升级。今年&#xff0c;苹果打破了常规&#xff0c;将四款新机型带入市场——iPhone 17、17 Pro、17 Pro Max&#xff0c;以及一款全新的成员&#xf…

站在资本投资领域如何看待分布式光纤传感行业?

近年来&#xff0c;资本投资领域对于分布式光纤传感行业并不十分敏感。这主要是由于分布式光纤传感技术是一个专业且小众的领域&#xff0c;其生命周期相对较长&#xff0c;缺乏爆发性&#xff0c;与消费品或商业模式创新产业有所不同。此外&#xff0c;国内的投资环境也是影响…

服务器上使用Docker部署sonarQube,并集成到Jenkins实现自动化。

目标是要在目标服务器上使用docker工具部署好sonar环境&#xff0c;然后再集成到Jenkins中实现自动化的代码审查工作。 Docker 首先Dokcer的源大部分现在都用不了&#xff0c;于是我上网查询&#xff0c;终于找到了一个可用的镜像。 编辑/etc/docker/daemon.json文件&#x…

医院存储文件采集至关重要,如何可靠安全进行?

医院的存储文件是医院日常运营中不可或缺的一部分&#xff0c;它包括了许多重要的文件类型&#xff1a; 病历档案&#xff1a;包括患者的门诊病历、住院病历、手术记录、护理记录等&#xff0c;是患者医疗过程的重要记录。 文书档案&#xff1a;医院在各项医疗业务活动、职能…

2023河南萌新联赛第(二)场 南阳理工学院

A. 国际旅行Ⅰ 题目&#xff1a; 思路&#xff1a; 因为题意上每个国家可以相互到达&#xff0c;所以只需要排序&#xff0c;输出第k小的值就可以了。 AC代码&#xff1a; #include<bits/stdc.h> #define int long long #define IOS ios::sync_with_stdio(0);cin.tie…

第一批进军AI的大学生,真的赚到钱了吗?

越来越多看到风口的大学生投身AI领域创业&#xff0c;这在ChatGPT&#xff08;美国人工智能公司OpenAI的大语言模型&#xff09;掀起新一轮人工智能浪潮后更加明显。 导读 壹 || 学生所处的学校环境和技术的结合更为紧密&#xff0c;因此学生可以利用这个信息差&#xff0c;用…

ZYNQ 入门笔记(零):概述

文章目录 引言产品线Zynq™ 7000 SoCZynq UltraScale™ MPSoCZynq UltraScale RFSoCVersal™ Adaptive SoC 开发环境 引言 Xilinx FPGA 产品线从经济型的 Spartan、Artix 系列到高性能的 Kintex、Virtex、Versal 系列&#xff0c;可以说涵盖了 FPGA 的绝大部分应用场景&#x…

Python爬虫实战案例(爬取图片)

爬取图片的信息 爬取图片与爬取文本内容相似&#xff0c;只是需要加上图片的url&#xff0c;并且在查找图片位置的时候需要带上图片的属性。 这里选取了一个4K高清的壁纸网站&#xff08;彼岸壁纸https://pic.netbian.com&#xff09;进行爬取。 具体步骤如下&#xff1a; …

使用阿里云云主机通过nginx搭建文件服务器

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、准备基础环境二、安装配置nginx三、阿里云安全组配置安全组配置 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/4ee96f38312e4771938e40f463987…

1 go语言环境的搭建

本专栏将从基础开始&#xff0c;循序渐进&#xff0c;由浅入深讲解Go语言&#xff0c;希望大家都能够从中有所收获&#xff0c;也请大家多多支持。 查看相关资料与知识库 专栏地址:Go专栏 如果文章知识点有错误的地方&#xff0c;请指正&#xff01;大家一起学习&#xff0c;…

【C语言】栈的实现(数据结构)

前言&#xff1a; 还是举一个生活中的例子&#xff0c;大家都玩过积木&#xff0c;当我们把积木叠起来的时候&#xff0c;如果要拿到最底部的积木&#xff0c;我们必须从顶端一个一个打出&#xff0c;最后才能拿到底部的积木&#xff0c;也就是后进先出&#xff08;先进后出&a…

项目的小结

1.实现实时聊天 1.服务端建立一个ConcurrentHashMap<> 用来存储在线用户&#xff0c;用户账号和socket然后&#xff0c;如果有个人发了信息&#xff0c;就去数据库中查询&#xff0c;然后根据这个在线用户进行传递信息 服务端框架&#xff1a; public class ServerMain {…

系统架构设计师教程 第4章 信息安全技术基础知识-4.3 信息安全系统的组成框架4.4 信息加解密技术-解读

系统架构设计师教程 第4章 信息安全技术基础知识-4.3 信息安全系统的组成框架 4.3 信息安全系统的组成框架4.3.1 技术体系4.3.1.1 基础安全设备4.3.1.2 计算机网络安全4.3.1.3 操作系统安全4.3.1.4 数据库安全4.3.1.5 终端安全设备4.3.2 组织机构体系4.3.3 管理体系4.4 信息加…

Ubuntu 22.04.4 LTS (linux) Tomcat 项目部署

1 war包直接放在tomcat webapps 下面 2 修改server.xml &#xff0c;改成自定义目录 sudo vim /data/tomcat/conf/server.xml <Host name"localhost" appBase"webapps" --> <Host name"localhost" appBase"" <Conte…