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

news2024/9/24 0:07:51

一窥模板的替换和匹配方式:偏特化的参数比泛化版本的还要多:判断是不是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.coloradmin.cn/o/1946031.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mindspore框架循环神经网络RNN模型实现情感分类|(六)模型加载和推理(情感分类模型资源下载)

Mindspore框架循环神经网络RNN模型实现情感分类 Mindspore框架循环神经网络RNN模型实现情感分类|&#xff08;一&#xff09;IMDB影评数据集准备 Mindspore框架循环神经网络RNN模型实现情感分类|&#xff08;二&#xff09;预训练词向量 Mindspore框架循环神经网络RNN模型实现…

【Vue实战教程】之 Vue Router 路由详解

Vue Router路由 1 路由基础 1.1 什么是路由 用Vue.js创建的项目是单页面应用&#xff0c;如果想要在项目中模拟出来类似于页面跳转的效果&#xff0c;就要使用路由。其实&#xff0c;我们不能只从字面的意思来理解路由&#xff0c;从字面上来看&#xff0c;很容易把路由联想…

CV13_混淆矩阵、F1分数和ROC曲线

1.1 混淆矩阵Confusion Matrix 混淆矩阵&#xff08;Confusion Matrix&#xff09;是机器学习和统计学中用于描述监督学习算法性能的特定表格布局。它是一种特定类型的误差矩阵&#xff0c;可以非常直观地表示分类模型在测试数据集上的预测结果与实际结果之间的对比。 混淆矩…

谣言检测文献阅读十二—A Convolutional Approach for Misinformation Identification

系列文章目录 谣言检测文献阅读一—A Review on Rumour Prediction and Veracity Assessment in Online Social Network谣言检测文献阅读二—Earlier detection of rumors in online social networks using certainty‑factor‑based convolutional neural networks谣言检测文…

FreeModbus学习——读输入寄存器eMBFuncReadInputRegister

FreeModbus版本&#xff1a;1.6 当功能码为04时&#xff0c;也就是读输入寄存器MB_FUNC_READ_INPUT_REGISTER 看一下它是怎么调用读输入寄存器处理函数的 当功能码为04时&#xff0c;调用读输入寄存器处理函数 这个函数在数组xFuncHandlers中&#xff0c;也就是eMBFuncRead…

Mysql数据库第四次作业

mysql> create table student(sno int primary key auto_increment,sname varchar(30) not null unique,Ssex varchar(2) check (Ssex男 or Ssex女) not null,Sage int not null,Sdept varchar(10) default计算机 not null); mysql> create table Course(Con int primar…

【通信协议-RTCM】MSM语句(2) - RINEXMSM7语句总结(重要!自动化开发计算卫星状态常用)

注释&#xff1a; 在工作中主要负责的是RTCM-MSM7语句相关开发工作&#xff0c;所以主要介绍的就是MSM7语句相关内容 1. 相位校准参考信号 2. MSM1、MSM2、MSM3、MSM4、MSM5、MSM6和MSM7的消息头内容 DATA FIELDDF NUMBERDATA TYPENO. OF BITSNOTES Message Number - 消息编…

1. Docker的介绍和安装 (二)

5 Docker的原理 5.1 Namespace Namespace&#xff08;命名空间&#xff09;提供了一个独立的工作环境&#xff0c;Docker使用Namespace来隔离容器&#xff0c;使得每个容器都有自己独立的系统资源&#xff08;如进程ID、主机名、网络等&#xff09;。 PID Namespace&#xf…

SBTI科学碳目标认证是什么?SBTI科学碳目标的重要性

SBTI科学碳目标认证&#xff0c;作为企业在应对气候变化和追求可持续发展道路上的重要里程碑&#xff0c;其认证过程严谨而系统。以下是获得SBTI科学碳目标认证的详细步骤&#xff1a; 首先&#xff0c;企业需要在线注册并提交承诺书&#xff0c;郑重承诺在未来24个月内提交科学…

Linux网络-配置IP

作者介绍&#xff1a;简历上没有一个精通的运维工程师。希望大家多多关注作者&#xff0c;下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 本来IP配置应该放在Linux安装完成的就要配置的&#xff0c;但是由于那个时候对Linux不怎么熟悉&#xff0c;所以单独列了一个…

每日一题 LeetCode03 无重复字符的最长字串

1.题目描述 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的最长字串的长度。 2 思路 可以用两个指针, 滑动窗口的思想来做这道题,即定义两个指针.一个left和一个right 并且用一个set容器,一个length , 一个maxlength来记录, 让right往右走,并且用一个set容器来…

扫雷-C语言

一、前言&#xff1a; 众所周知&#xff0c;扫雷是一款大众类的益智小游戏&#xff0c;它的游戏目标是在最短的时间内根据点击格子出现的数字找出所有非雷格子&#xff0c;同时避免踩雷&#xff0c;踩到一个雷即全盘皆输。 今天&#xff0c;我们的目的就是通过C语言来实现一个简…

Open函数使用 Json与pickle Os模块

一. 文件操作与 open() 函数 Open函数是Python中用于打开文件的内置函数&#xff0c;其基本语法如下&#xff1a; open(file, moder, buffering-1, encodingNone, errorsNone, newlineNone, closefdTrue, openerNone) 各参数说明&#xff1a; file&#xff1a; 要打开的文件…

34_YOLOv5网络详解

1.1 简介 YOLOV5是YOLO&#xff08;You Only Look Once&#xff09;系列目标检测模型的一个重要版本&#xff0c;由 Ultralytics 公司的Glenn Jocher开发并维护。YOLO系列以其快速、准确的目标检测能力而闻名&#xff0c;尤其适合实时应用。YOLOV5在保持高效的同时&#xff0c…

El-Table 表格的表头字段切换

最近写了一个小功能&#xff0c;比较有意思&#xff0c;特此博客记录。 提出需求&#xff1a;需要表头字段变化&#xff0c;但是我在官网上的表格相关上查找&#xff0c;没有发现便捷方法。 于是我有两个想法&#xff1a;1.做三个不同的表格。2.做一个表格使用不同的表头字段。…

2024.7.24 远程连接到另一设备(win)上的vrep时无响应(防火墙!)

Windows防火墙禁止了软件的端口的通信&#xff0c;打开即可 如何设置Windows 7 防火墙端口规则

字典集合案例

1.统计字符 统计字符串中每个字符出现的次数 s l like summer very much #去掉空格 s s.replace(" ","") d dict() for i in s:if i in d:d[i] 1else:d[i] 1 for i in d:print(i,d[i]) 2.求不重复的随机数 #导入随机数 import random a int(input(&q…

VMware 上安装 CentOS 7 教程 (包含网络设置)

**建议先看一些我安装VMware的教程&#xff0c;有些网络配置需要做一下 1.打开VMware&#xff0c;创建虚拟机 2.勾选自定义&#xff0c;点击下一步 3.点击下一步 4.勾选“稍后安装操作系统”&#xff0c;点击下一步 5.勾选linux&#xff0c;勾选centos7&#xff0c;点击下一步…

每日Attention学习12——Exterior Contextual-Relation Module

模块出处 [ISBI 22] [link] [code] Duplex Contextual Relation Network for Polyp Segmentation 模块名称 Exterior Contextual-Relation Module (ECRM) 模块作用 内存型特征增强模块 模块结构 模块思想 原文表述&#xff1a;在临床环境中&#xff0c;不同样本之间存在息肉…

Python算法基础:解锁冒泡排序与选择排序的奥秘

在数据处理和算法设计中&#xff0c;排序是一项基础且重要的操作。本文将介绍两种经典的排序算法&#xff1a;冒泡排序&#xff08;Bubble Sort&#xff09;和选择排序&#xff08;Selection Sort&#xff09;。我们将通过示例代码来演示这两种算法如何对列表进行升序排列。 一…