C++学习笔记----11、模块、头文件及各种主题(一)---- 模板概览与类模板(6)

2.5.1、带有非类型的模板参数的成员函数模板

        前面的HEIGHT与WIDTH整型模板参数的Grid类模板的主要问题是,高度与宽度变成了类型的一部分。这种限制妨碍 了将一个高度与宽度的网格赋值给一个不同高度与宽度的网格。在有些场景中,是需要赋值或拷贝一种大小的网格到一个不同大小的网格的。不是合目标对象成为源对象的完美克隆,而是只拷贝那些源数组中的元素匹配到目的数组中,如果源数组在任何维度上小于目标数组的话,用缺省省填充目标数组。用成员函数模板的赋值操作符与拷贝构造函数,可以精确地做到这一点,这就允许了赋值与拷贝不同大小的网格。下面是类定义:

export
template <typename T, std::size_t WIDTH = 10, std::size_t HEIGHT = 10>
class Grid
{
public:Grid() = default;virtual ~Grid() = default;// Explicitly default a copy constructor and copy assignment operator.Grid(const Grid& src) = default;Grid& operator=(const Grid& rhs) = default;// Explicitly default a move constructor and move assignment operator.Grid(Grid&& src) = default;Grid& operator=(Grid&& rhs) = default;template <typename E, std::size_t WIDTH2, std::size_t HEIGHT2>Grid(const Grid<E, WIDTH2, HEIGHT2>& src);template <typename E, std::size_t WIDTH2, std::size_t HEIGHT2>Grid& operator=(const Grid<E, WIDTH2, HEIGHT2>& rhs);void swap(Grid& other) noexcept;std::optional<T>& at(std::size_t x, std::size_t y);const std::optional<T>& at(std::size_t x, std::size_t y) const;std::size_t getHeight() const { return HEIGHT; }std::size_t getWidth() const { return WIDTH; }private:void verifyCoordinate(std::size_t x, std::size_t y) const;std::optional<T> m_cells[WIDTH][HEIGHT];
};

        新的定义包含了成员函数模板的拷贝构造函数与赋值操作符,加一个辅助成员函数swap()。注意非参数化的拷贝构造函数与赋值操作符显式地缺省(因为有用户声明的析构函数)。它们只是拷贝可赋值m_cells从源到目标,这正是想要的两个同样大小的网格的语法。

        下面是参数化的拷贝构造函数:

template <typename T, std::size_t WIDTH, std::size_t HEIGHT>
template <typename E, std::size_t WIDTH2, std::size_t HEIGHT2>
Grid<T, WIDTH, HEIGHT>::Grid(const Grid<E, WIDTH2, HEIGHT2>& src)
{for (std::size_t i{ 0 }; i < WIDTH; ++i) {for (std::size_t j{ 0 }; j < HEIGHT; ++j) {if (i < WIDTH2 && j < HEIGHT2) {m_cells[i][j] = src.at(i, j);}else {m_cells[i][j].reset();}}}
}

        注意拷贝构造函数只是拷贝了WIDTH与HEIGHT元素的x与y维度,各自地从src,甚至如果src比目标大。如果src在任一维度小于目标,std::optional对象在额外的点上使用reset()成员函数重置。

        下面是swap()与operator=的实现:

template <typename T, std::size_t WIDTH, std::size_t HEIGHT>
void Grid<T, WIDTH, HEIGHT>::swap(Grid& other) noexcept
{std::swap(m_cells, other.m_cells);
}template <typename T, std::size_t WIDTH, std::size_t HEIGHT>
template <typename E, std::size_t WIDTH2, std::size_t HEIGHT2>
Grid<T, WIDTH, HEIGHT>& Grid<T, WIDTH, HEIGHT>::operator=(const Grid<E, WIDTH2, HEIGHT2>& rhs)
{// Copy-and-swap idiomGrid<T, WIDTH, HEIGHT> temp{ rhs }; // Do all the work in a temporary instance.swap(temp); // Commit the work with only non-throwing operations.return *this;
}

2.5.2、使用带有Explicit对象参数的成员函数模板来避免代码重复(C++23)

        我们运行的Grid类模板的例子带有一个单独的模板类型参数T,包含了at()成员函数的两个重载,const与non-const。提醒一下:

export template <typename T>
class Grid
{
public:std::optional<T>& at(std::size_t x, std::size_t y);const std::optional<T>& at(std::size_t x, std::size_t y) const;// Remainder omitted for brevity
};

        它们的实现使用了Scott Meyers的const_cast()模式来避免代码重复:

template <typename T>
const std::optional<T>& Grid<T>::at(std::size_t x, std::size_t y) const
{verifyCoordinate(x, y);return m_cells[x + y * m_width];
}template <typename T>
std::optional<T>& Grid<T>::at(std::size_t x, std::size_t y)
{return const_cast<std::optional<T>&>(std::as_const(*this).at(x, y));
}

        虽然没有代码重复,仍然需要显式定义const与non-const重载。从C++23开始,可以使用explicit object parameter来避免必须显式提供两种重载。其秘诀在于将at()成员函数墨迹为成员函数模板,显式对象参数self的类型是其自身,是一个模板类型参数Self,这样就能自动推演了。这个特性叫做duducing this。下面是这样的一个声明:

export template <typename T>
class Grid
{
public:template <typename Self>auto&& at(this Self&& self, std::size_t x, std::size_t y);// Remainder omitted for brevity
};

        实现使用了传递引用Self&&;看下面的注意,这样的传递引用可以绑定Grid<T>&,const Grid<T>&,与Grid<T>&&。

        注意:类型Self&&的引用只是一个传递引用,当它用作函数或成员函数模板的参数时,使用Self作为它的一个模板类型参数。如果类成员函数有一个Self&&参数,但是带有类的Self模板类型参数,并且不是成员函数自身,那么 Self&&就不是一个引用传递,只是一个右值引用。这是因为编译器开始处理带有Self&&参数的成员函数时,类模板参数Self早已解析成了具体的类型,例如int,并且在当时,该成员函数的参数类型也已经被替换成了int&&。

        下面是实现。记住使用显式对象参数的成员函数体内,需要使用显式对象参数,在本例中是self,来得到访问对象的权限;没有this指针。

template <typename T>
template <typename Self>
auto&& Grid<T>::at(this Self&& self, std::size_t x, std::size_t y)
{self.verifyCoordinate(x, y);return std::forward_like<Self>(self.m_cells[x + y * self.m_width]);
}

        实现使用了C++23中引入的std::forward_like<Self>(x)。它返回一个对x的引用,使用了与Self&&类似的属性。这样,由于m_cells的元素类型为optional<T>,有如下结论:

  • 如果Self&&绑定了Grid<T>&,返回类型为optional<T>&。
  • 如果Self&&绑定了const Grid<T>&,返回类型为const optional<T>&。
  • 如果Self&&绑定了Grid<T>&&,返回类型为optional<T>&&。

        总结一下,有了成员函数模板,显式对象参数,传递引用,与forward_like()的组合,就能够声明与定义单个成员函数来提供const与non-const的实例了。

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

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

相关文章

Java项目实战II基于Spring Boot的疗养院管理系统设计与实现(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 随着人口老…

Canny边缘检测中Hysteresis Thresholding(滞后阈值)名字的由来

Hysteresis Thresholding直译是滞后阈值。注意区分hysteresis、heuristic、hypothesis。 Hysteresis&#xff1a;在物理学中指滞后现象。 Canny边缘检测中滞后阈值这个名字来源于物理学中的滞后现象。通过设置两个不同的阈值来决定哪些像素属于边缘。这两个阈值分别是高阈值&…

[ Linux 命令基础 6 ] Linux 命令详解-权限和用户管理命令

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

# ubuntu创建新用户和它的家目录

ubuntu创建新用户和它的家目录 一、使用 useradd命令创建新用户和它的家目录&#xff1a; 1、命令如下&#xff1a; #sudo useradd -r -m -s /bin/bash userName #如&#xff1a;sudo useradd -r -m -s /bin/bash zhangsan2、命令参数解释 -r : 建立系统账号。 -m : 自动建…

网线类别线芯含义和传输距离以及水晶头制作标准

网线八芯每根的含义&#xff1a; 网线的八根线芯&#xff0c;也被称为RJ45网线中的8芯&#xff0c;网线采用8根线芯&#xff0c;这八根线芯各自承担着特定的功能。这8根线芯被分为4对&#xff0c;每对以特定的方式绞合在一起&#xff0c;8芯网线主要是为了减少电磁信号的相互干…

HTB:Sightless[WriteUP]

目录 连接至HTB服务器并启动靶机 使用nmap对靶机TCP端口进行开放扫描 继续使用nmap对靶机开放的TCP端口进行脚本、服务扫描 首先尝试对靶机FTP服务进行匿名登录 使用curl访问靶机80端口 使用浏览器可以直接访问该域名 使用浏览器直接访问该子域 Getshell 横向移动 查…

Golang | Leetcode Golang题解之第554题砖墙

题目&#xff1a; 题解&#xff1a; func leastBricks(wall [][]int) int {cnt : map[int]int{}for _, widths : range wall {sum : 0for _, width : range widths[:len(widths)-1] {sum widthcnt[sum]}}maxCnt : 0for _, c : range cnt {if c > maxCnt {maxCnt c}}retur…

斯坦福泡茶机器人DexCap源码解析:涵盖收集数据、处理数据、模型训练三大阶段

前言 因为我司「七月在线」关于dexcap的复现/优化接近尾声了&#xff0c;故准备把dexcap的源码也分析下。​下周则分析下iDP3的源码——为队伍「iDP3人形的复现/优化」助力 最开始&#xff0c;dexcap的源码分析属于此文《DexCap——斯坦福李飞飞团队泡茶机器人&#xff1a;带…

高中数学:概率-随机实验、样本空间、随机事件

文章目录 一、随机实验二、样本空间三、随机事件例题 四、事件运算 一、随机实验 二、样本空间 三、随机事件 例如 样本空间 Ω { a , b , c , d , e , f } 则&#xff0c;事件 A { a , b , c } &#xff0c;是一个随机事件 事件 B { d } 是一个基本事件 样本空间Ω\{a,b,c…

w~大模型~合集21

我自己的原文哦~ https://blog.51cto.com/whaosoft/12459590 #大模型~微调~用带反馈的自训练 面对当前微调大模型主要依赖人类生成数据的普遍做法&#xff0c;谷歌 DeepMind 探索出了一种减少这种依赖的更高效方法。大模型微调非得依赖人类数据吗&#xff1f;用带反馈的自训…

利用 Vue.js 开发动态组件的实战指南

&#x1f4dd;个人主页&#x1f339;&#xff1a;一ge科研小菜鸡-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; Vue.js 是现代 Web 开发中非常流行的框架&#xff0c;以其渐进式架构和组件化设计受到广泛欢迎。组件化开发是 Vue.js 的核心优势…

Jmeter中的配置原件(一)

配置原件 1--CSV Data Set Config 用途 参数化测试&#xff1a;从CSV文件中读取数据&#xff0c;为每个请求提供不同的参数值。数据驱动测试&#xff1a;使用外部数据文件来驱动测试&#xff0c;使测试更加灵活和可扩展。 配置步骤 准备CSV文件 创建一个CSV文件&#xff0c…

MCU的OTA升级(未完-持续更新)

1.术语 ISP : In-System Programming 在系统编程&#xff0c;是一种通过MCU&#xff08;微控制器单元&#xff09;上的内置引导程序&#xff08;BootLoader&#xff09;来实现对芯片内部存储器&#xff08;如Flash&#xff09;进行编程的技术。 华大目前对应的ISP IAP&…

让redis一直开启服务/自动启动

文章目录 你的redis是怎么打开的黑窗不能关?必须要自动启动吗?再说说mysql 本文的所有指令都建议在管理员权限下打开cmd控制台 推荐的以管理员身份打开控制台的方式 Win R 打开运行 输入cmdShift Ctrl Enter 你的redis是怎么打开的 安装过redis的朋友都知道, redis的安…

从认识 VNode VDOM 到实现 mini-vue

前言 现有框架几乎都引入了虚拟 DOM 来对真实 DOM 进行抽象&#xff0c;也就是现在大家所熟知的 VNode 和 VDOM&#xff0c;那么为什么需要引入虚拟 DOM 呢&#xff1f;下面就一起来了解下吧&#xff01;&#xff01;&#xff01; VNode & VDOM VNode 和 VDOM 是什么&am…

vue项目实战

1.项目文件夹添加&#xff08;结构如下&#xff09; 2.页面构建 安装路由 npm install react-router-dom 3.页面基本模板 router文件夹下index.js的模板 // 引入组件 import Login from "../views/login"; // 注册路由数组 const routes [{// 首页默认是/path: …

SD-WAN跨境加速专线:打造无缝、高效的全球社交媒体营销网络

在数字化时代&#xff0c;电子商务与社交媒体的融合已成为不可逆转的趋势。亚马逊&#xff0c;作为全球领先的电子商务平台&#xff0c;近期与Facebook、Instagram、Snapchat、Pinterest和TikTok等社交媒体巨头携手&#xff0c;推出了一项革命性的无缝购物体验。这一创新举措不…

yelp商家数据集上使用火算法求解TSP 问题

先简要回顾下什么是TSP问题&#xff0c; 旅行商问题&#xff08;Traveling Salesman Problem&#xff0c;TSP&#xff09;是一个经典的组合优化问题&#xff0c;广泛应用于运筹学、计算机科学和物流等领域。TSP的基本描述如下&#xff1a; 问题描述 定义&#xff1a;假设有一…

【深度学习目标检测|YOLO算法1】YOLO家族进化史:从YOLOv1到YOLOv11的架构创新、性能优化与行业应用全解析...

【深度学习目标检测|YOLO算法1】YOLO家族进化史&#xff1a;从YOLOv1到YOLOv11的架构创新、性能优化与行业应用全解析… 【深度学习目标检测|YOLO算法1】YOLO家族进化史&#xff1a;从YOLOv1到YOLOv11的架构创新、性能优化与行业应用全解析… 文章目录 【深度学习目标检测|YOL…

星期-时间范围选择器 滑动选择时间 最小粒度 vue3

星期-时间范围选择器 功能介绍属性说明事件说明实现代码使用范例 根据业务需要&#xff0c;实现了一个可选择时间范围的周视图。用户可以通过鼠标拖动来选择时间段&#xff0c;并且可以通过快速选择组件来快速选择特定的时间范围。 功能介绍 时间范围选择&#xff1a;用户可以…