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

C++学习笔记----11、模块、头文件及各种主题(二)---- 函数模板(2)

3、函数模板作为类模板的朋友

        在类模板中,当想要重载操作符时,函数模板是有用的。例如,可能想要重载Grid类模板的加操作符(operator+)以便能够使两个Grid相加。结果是与两个操作数中最小的Grid相同大小的Grid。只有两个网格都含有一个真实的值时,对应的网格才会相加在一起。假设想使operator+成为一个单独的函数模板。其定义会在Grid.cppm模块接口文件中,看起来如下。实现使用了std::min(),定义在<algorithm>,返回两个给定值中较小的那个。

export
template <typename T>
Grid<T> operator+(const Grid<T>& lhs, const Grid<T>& rhs)
{std::size_t minWidth{ std::min(lhs.m_width, rhs.m_width) };std::size_t minHeight{ std::min(lhs.m_height, rhs.m_height) };Grid<T> result{ minWidth, minHeight };for (std::size_t y{ 0 }; y < minHeight; ++y) {for (std::size_t x{ 0 }; x < minWidth; ++x) {const auto& leftElement{ lhs.at(x, y) };const auto& rightElement{ rhs.at(x, y) };if (leftElement.has_value() && rightElement.has_value()) {result.at(x, y) = leftElement.value() + rightElement.value();}}}return result;
}

        为了查询optional是否包含一个真实的值,使用has_value()成员函数,而value()用于查询该值。

        该函数模板作用于任何Grid,只要保存在grid中的元素类型有加操作符。该实现唯一的问题是它访问Grid类的私有成员m_width与m_height。很明显的解决方案是使用公共的getWidth()与getHeight()成员函数,但是让我们看一个如何能够使函数模板成为类模板的朋友。在这个例子中,可以使操作符成为Grid类模板的朋友。然而,Grid与operator+都是模板。你其实想要的是每个特别的类型T的operator+的每个实例都成为Grid模板相同类型的实例的一个朋友。语法看起来像这样:

export template <typename T>
class Grid
{
public:friend Grid operator+<T>(const Grid& lhs, const Grid& rhs);// Omitted for brevity
};

        该模板朋友的声明有点搞:你要说的是,对于类型T的类模板的实例,operator+的T的实例化是一个朋友。换句话说,在类实例与函数实例之间有一对一的朋友影射。需要特别注意的是,在operator+上的<T>的显示规格。该语法告诉编译器operator+自身是一个模板。

        该朋友operator+可以测试如下。如下的代码首先定义了两个辅助函数模板:fillGrid(),它用递增的数字填充了Grid,printGrid(),它打印任何Grid到控制台。

import grid;
import std;using namespace std;template<typename T>
void fillGrid(Grid<T>& grid)
{T index{ 0 };for (size_t y{ 0 }; y < grid.getHeight(); ++y) {for (size_t x{ 0 }; x < grid.getWidth(); ++x) {grid.at(x, y) = ++index;}}
}template<typename T>
void printGrid(const Grid<T>& grid)
{for (size_t y{ 0 }; y < grid.getHeight(); ++y) {for (size_t x{ 0 }; x < grid.getWidth(); ++x) {const auto& element{ grid.at(x, y) };if (element.has_value()) {print("{}\t", element.value());} else {print("n/a\t");}}println("");}
}int main()
{Grid<int> grid1{ 2, 2 };Grid<int> grid2{ 3, 3 };fillGrid(grid1);println("grid1:");printGrid(grid1);fillGrid(grid2);println("\ngrid2:");printGrid(grid2);auto result{ grid1 + grid2 };println("\ngrid1 + grid2:");printGrid(result);
}

4、模板类型参数推断的更多内容

        编译器基于传递给函数模板的参数来推断函数模板参数的类型。无法推断出的模板参数需要显示指定。

        例如,下面的add()函数模板要求三个模板参数:返回值的类型与两个操作数的类型:

template <typename RetType, typename T1, typename T2>
RetType add(const T1& t1, const T2& t2) { return t1 + t2; }

        可以指定三个参数来调用该函数模板如下:

auto result { add<long long, int, int>(1, 2) };

        然而,因为模板参数T1与T2是函数的参数,编译器可以推断出这两个参数,所以可以只指定返回值的类型来调用add():

auto result { add<long long>(1, 2) };

        只有在推断参数为参数列表中排在最后时才有效。假定函数模板定义如下:

template <typename T1, typename RetType, typename T2>
RetType add(const T1& t1, const T2& t2) { return t1 + t2; }

        就需要指定RetType,因为编译器无法推断出其类型。然而,因为RetType是第二个参数,所以也必须显示指定T1:

auto result { add<int, long long>(1, 2) };

        也可以为返回类型模板参数提供一个缺省值,这样的话就可以不指定任何类型来调用add():

template <typename RetType = long long, typename T1, typename T2>
RetType add(const T1& t1, const T2& t2) { return t1 + t2; }
...
auto result { add(1, 2) };


http://www.mrgr.cn/news/70804.html

相关文章:

  • 高性能Web网关:OpenResty 基础讲解
  • 低空载功耗,高能源利用率 BDA5-20W BOSHIDA DCDC
  • 阿里巴巴通义灵码推出Lingma SWE-GPT:开源模型的性能新标杆
  • 【Elasticsearch】Elasticsearch集成Spring Boot
  • EasyExcel级联下拉
  • 【Linux】软件安装目录的选择
  • VirtIO实现原理(2)
  • Python酷库之旅-第三方库Pandas(207)
  • 金山云C++面试题及参考答案
  • Python学习:scipy是什么?
  • 关于cloacked-pixel-master在kali上的安装
  • C++线程
  • Java期末复习暨学校第四次上机课作业
  • 【含文档】基于ssm+jsp的校园疫情管理系统(含源码+数据库+lw)
  • NLP论文速读(NeurIPS2024)|使用视觉增强的提示来增强视觉推理
  • SQLite Where 子句
  • 从2D到3D:MoGe——微软的单目3D几何重建模型
  • Python CSV文件列合并实战:从基础到进阶
  • [数组二分查找] 0374. 猜数字大小
  • 知名开源项目官宣停更,太痛了!
  • (66)RLS均衡器和LMS均衡器作用于通过频率选择性衰落信道的16-QAM信号的性能对比MATLAB仿真
  • Python函数专题:偏函数
  • halcon拉普拉斯算子
  • 【优选算法】探索双指针之美(一): 同向双指针缔造滑动窗口
  • SpringBoot(十二)SpringBoot配置redis
  • 使用金鸣识别在线网页版将行驶证转为结构化Excel教程