(C++) 函数重载机制

文章目录

  • 🔢前言
    • 🕹️参考资料
    • 🕹️实例代码
  • 🔢重载机制
    • 🥇名称查找
    • 🥈模板函数处理
    • 🥉重载决议
  • END
    • 关注我

🔢前言

在C++中函数重载是一个非常强大由复杂的问题。

在C++中本身就有许多函数机制,加上该语言也在不断的迭代,规则是越来越多。

🕹️参考资料

C++ Insights (cppinsights.io)

C++20高级编程 (豆瓣) (douban.com)

第2章 编译时多态

2.1 函数重载机制

函数重载有三个步骤

  1. 名称查找
  2. 模板函数处理
  3. 重载决议

其中返回值不参与以上函数重载考虑体系。

🕹️实例代码

下方为书中的实例的整理代码。

#include <iostream>

#define LOG() std::cout << "[" << __LINE__ << "]" << __PRETTY_FUNCTION__ << std::endl

namespace animal {
struct Cat {};

void feed(Cat* foo, int) {
    LOG();
}
}  // namespace animal

struct CatLike {
    CatLike(animal::Cat*) {
        LOG();
    }
};

void feed(CatLike) {
    LOG();
}

template <typename T>
void feed(T*, double) {
    LOG();
}

template <>
void feed(animal::Cat*, double) {
    LOG();
}

int main() {
    animal::Cat cat;
    feed(&cat, 0);
}

先说结论,本代码的结果为:

[10]void animal::feed(animal::Cat*, int)

🔢重载机制

🥇名称查找

通常分三类:

  • 成员函数查找
  • 限定名称查找
  • 未限定名称查找

成员函数查找

使用.,->进行成员调用时。

限定名称查找

使用::进行namespace或者class-name时。

未限定名称查找

根据参数依赖查找规则**(Argument-Dependent Lookup,简称ADL)** 。

在上述例子中,可以筛选出下面的候选项。

void animal::feed(Cat* foo, int);
void feed(CatLike);
template <typename T> void feed(T*, double);

ADL规则相关

ADL仅在未限定名称查找中作用。

典型应用:

#include <iostream>

int main() {
    operator<<(std::cout, "Hello World\n");
}

强制避免ADL

// 套括号,使函数的直接调用变为函数指针的转换
(feed)(&cat, 0);

模板函数相关

名称查找只考虑普通函数和主模板

模板特化在重载决议部分考虑。

🥈模板函数处理

注意SFINAE不会导致编译失败。

示例中的模板函数通过第一部分,在该阶段展开为:

void feed<animal::Cat>(animal::Cat*, double);

现在还是有三个候选集:

void animal::feed(Cat* foo, int);
void feed(CatLike);
void feed<animal::Cat>(animal::Cat*, double);

🥉重载决议

重载决议分为两步:

  1. 规约可行函数集
  2. 挑选最佳可行函数

规约可行函数集

  1. 如果调用函数有m个实参,那么可行函数必须有m个形参
  2. 如果候选函数少于m个形参,但最后一个参数是可变参数,则为可行函数。
  3. 如果候选函数多余m个形参,但从m+1到最后的形参都拥有默认参数,则为可行函数。在挑选最佳可行函数时只考虑前m个形参。
  4. 从C++20起,如果函数有约束,则必须符合约束。
  5. 可行需要保证每个形参类型即使通过隐式转换后也能与实参类型对得上。

简单说就是参数个数,类型转换,约束。

经过此轮决议,剩下候选集:

void animal::feed(Cat* foo, int);
void feed<animal::Cat>(animal::Cat*, double);

挑选最佳可行函数

最佳的规则比较多,下面是比较重要几条(并按强度的顺序给出)

  1. 形参与实参类型最匹配,转换最少。
  2. 非模板函数优于模板函数。
  3. 若有多个模板实例,那么最具体的最佳。
  4. C++20起,若函数有约束,则约束更强的最佳。

下面分别对这几条规则说明

规则1

形参与实参类型最匹配,转换最少。

// [1]
void fun(int) {}
// [2]
void fun(double) {}

int main() {
    // [1]
    fun(1);
}

规则2

非模板函数优于模板函数。

// [1]
void fun(int) {}

// [2]
template <typename T>
void fun(T) {}

int main() {
    // [1]
    fun(1);
}

规则3

若有多个模板实例,那么最具体的最佳。

// [1]
template <typename T>
void fun(T) {}

// [2]
template <typename T>
void fun(T*) {}

int main() {
    int x;
    // [2]
    fun(&x);
}
template <typename T>
void fun(T) {}

#ifdef INSIGHTS_USE_TEMPLATE
template <>
void fun<int *>(int *);
#endif

template <typename T>
void fun(T *) {}

/* First instantiated from: insights.cpp:13 */
#ifdef INSIGHTS_USE_TEMPLATE
template <>
void fun<int>(int *) {}
#endif

int main() {
    int x;
    fun(&x);
    return 0;
}

规则4

C++20起,若函数有约束,则约束更强的最佳。

#include <iostream>
#include <type_traits>

// 概念:要求类型 T 必须是整数
template <typename T>
concept Integer = std::is_integral_v<T>;

// 概念:要求类型 T 必须是有符号整型
template <typename T>
concept SignedIntegral = std::is_integral_v<T> && std::is_signed_v<T>;

// [1]
template <Integer T>
void fun(T value) {
    std::cout << __LINE__ << std::endl;
}

// [2]
template <SignedIntegral T>
void fun(T value) {
    std::cout << __LINE__ << std::endl;
}

int main() {
    // [1]
    fun(42u);
}
#include <iostream>
#include <type_traits>

template <typename T>
concept Integer = std::is_integral_v<T>;

template <typename T>
concept SignedIntegral = std::is_integral_v<T> && std::is_signed_v<T>;

template <Integer T>
void fun(T value) {
    std::cout.operator<<(15).operator<<(std::endl);
}

/* First instantiated from: insights.cpp:26 */
#ifdef INSIGHTS_USE_TEMPLATE
template <>
void fun<unsigned int>(unsigned int value) {
    std::cout.operator<<(15).operator<<(std::endl);
}
#endif

template <SignedIntegral T>
void fun(T value) {
    std::cout.operator<<(21).operator<<(std::endl);
}

#ifdef INSIGHTS_USE_TEMPLATE
template <>
void fun<unsigned int>(unsigned int value);
#endif

int main() {
    fun(42U);
    return 0;
}



END

关注我

关注我,学习更多C/C++,算法,计算机知识

B站:

👨‍💻主页:天赐细莲 bilibili

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

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

相关文章

外汇天眼:金融服务补偿计划(FSCS)确认已任命清算人为TenetConnect Services有限公司

2024年6月5日&#xff0c;Tenet Group有限公司的董事们任命了Interpath有限公司的Ed Boyle、Howard Smith和Rob Spence为联合清算人。Ed Boyle和Rob Spence也被任命为其子公司Tenet有限公司、TenetConnect有限公司和TenetConnect Services有限公司的联合清算人。Tenet Mortgage…

手把手Linux高可hadoop集群的搭建

高可用集群的搭建 在搭建高可用集群之前&#xff0c;如果搭建了完全分布式hadoop&#xff0c;先执行stop-all.sh停掉所有的服务&#xff0c;只保留jdk和zookeeper的2个服务&#xff0c;然后再去搭建。 目标&#xff1a; 高可用集群简介部署Hadoop高可用集群 一&#xff0e;…

备战618!各广告平台SDK版本更新;最新支持eCPR指标;新增自动创建广告源平台 | TopOn产品更新

「TopPro 每月产品速递」是由TopOn最新推出的产品专栏&#xff0c;将会以月为周期梳理TopOn最新产品动态&#xff0c;致力于为互联网从业者提供优质服务&#xff0c;引领行业产品发展。 TopPro | 3~5月产品速递 2024.03.01-05.30 01 eCPR指标支持 // 功能描述 TopOn后台支…

2.1 初识Windows程序

Windows程序设计是一种面向对象的编程。Windows操作系统以数据结构的形式定义了大量预定义的对象作为操作系统的数据类型。Windows动态链接库提供了各种各样的API接口函数供Windows应用程序调用。一个Windows应用程序是运行在Windows操作系统之上的。这些API接口函数的调用所实…

大学汉语言文学古代汉语/中国古代文学试题及答案,分享几个实用搜题和学习工具 #其他#微信#知识分享

大学生搜题软件是一种方便快捷的工具&#xff0c;可以帮助大学生们在解答问题和完成作业时节省时间和精力。 1.彩虹搜题 这是个老公众号了 界面简洁友好&#xff0c;操作简单易上手。无论你是谁&#xff0c;都能轻松搜题。 下方附上一些测试的试题及答案 1、《中华人民共和…

MySQL8 全文索引

文章目录 创建索引使用索引总结 创建索引 之前未尝试过使用MySQL8的全文索引&#xff0c;今天试一试看看什么效果&#xff0c;否则跟不上时代了都。   创建索引非常简单&#xff0c;写句SQL就行。 create table goods(id integer primary key auto_increment,name varchar(2…

铁塔、烟囱建筑倾斜监测的倾角仪的分类以及工作原理

前言 倾角传感器是一种用于测量物体相对平面倾斜角度的仪器。倾角传感器又称作倾角仪、倾斜仪、测斜仪、水平仪、倾角计&#xff0c;经常用于物体的水平角度变化的精确测量&#xff0c;用它可测量被测平面相对于水平位置的倾斜度、两部件相互平行度和垂直度&#xff1b;已成为桥…

蓝卓热电行业解决方案

能源是人类社会发展过程中的永恒话题,热电联产作为电能和热能同时生产的能源利用形式,相较传统的火力发电具有能源利用效率高等优点,可以高效解决能源及环境问题。目前&#xff0c;世界各国都将热电联产作为更高效、更环保的能源供给体系而有效措施大力推广。 如何降本增效、减…

组件的注册和引用

在Vue中&#xff0c;开发者可以将页面中独立的、可重用的部分封装成组件&#xff0c;对组件的结构&#xff0c;样式和行为进行设置。组件是 Vue 的基本结构单元&#xff0c;组件之间可以相互引用。 一.注册组件 当在Vue项目中定义了一个新的组件后&#xff0c;要想在其他组件中…

【全开源】防伪溯源一体化管理系统源码(FastAdmin+ThinkPHP+Uniapp)

&#x1f50d;防伪溯源一体化管理系统&#xff1a;守护品质&#xff0c;追溯无忧 一款基于FastAdminThinkPHP和Uniapp进行开发的多平台&#xff08;微信小程序、H5网页&#xff09;溯源、防伪、管理一体化独立系统&#xff0c;拥有强大的防伪码和溯源码双码生成功能&#xff0…

为何瑞士银行成了富人的“保险箱”?

​瑞士银行&#xff0c;这个名字大家耳熟能详&#xff0c;为啥呢&#xff1f;因为它被誉为“全球最安全银行”。那么&#xff0c;这“最安全”的名头是怎么来的呢&#xff1f;它的金库又藏在哪儿呢&#xff1f; 话说在1930年代&#xff0c;德国纳粹迫害犹太人&#xff0c;导致…

政安晨【零基础玩转各类开源AI项目】解析开源:IDM-VTON:改进真实虚拟试穿的扩散模型

目录 概述 要求 数据准备 服饰代码 推理 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: 零基础玩转各类开源AI项目 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 项目地址&…

STM32-电灯,仿真

目录 前言: 一. 配置vscode 二. 新创建软件工程 三. 仿真 1.新建工程想到,选择名称和路径 2.从选中的模板创建原理图 3.不创建PCB布版设计 4.选择没有固件项目 5.完成 四.源码 五. 运行效果 六. 总结 前言: 这篇主要是配置vscode和创建仿真,和点灯的完整代码,欢迎大…

nodejs---fs模块,文件读写操作详解,自定义一个文件写入方法

fs模块导入 Node.js 同时支持 CommonJS 和 ES 模块系统&#xff08;自 Node.js v12 以来&#xff09; // 两种模块导入方式 import * as fs from fs;// Es6:这种方式需要在package.json中配置"type": "module" const fs require(fs);// commonJs:如果你…

肥胖与代谢综合征,膳食纤维干预的相关进展

谷禾健康 肥胖和代谢综合征在全球范围内日益流行&#xff0c;是21世纪人类健康面临的重大威胁之一。据世界卫生组织(WHO)全球数据估计&#xff0c;目前全球约13%(即近65亿)成年人口受肥胖症影响。 肥胖和代谢综合征对健康的危害包括增加患心血管疾病、糖尿病和高血压的风险&…

短视频矩阵系统----可视化剪辑独立开发(采用php)

短视频矩阵系统源头技术开发&#xff1a; 打磨短视频矩阵系统的开发规则核心框架可以按照以下几个步骤进行&#xff1a; 明确系统需求&#xff1a;首先明确系统的功能需求&#xff0c;包括短视频的上传、编辑、发布、播放等环节。确定系统的目标用户和主要的使用场景&#xff…

智能数据分析(1)Lecture 6-8b

Lecture 6: Generative Models 生成模型 vs 判别模型 判别模型&#xff08;Discriminative Models&#xff09; 判别模型的主要任务是直接学习输入 x x x 和类别 y y y 之间的关系。它们不关心数据的生成过程&#xff0c;而是直接估计类别的边界。 定义&#xff1a;判别模…

Win10系统无法安装msi文件问题

winR输入services.msc打开服务 找到Windows Installer并启动 输入msiexec /package “msi文件路径”

perccli查看磁盘和Raid卡

1、安装 source /etc/profile chmod 755 /usr/sbin/perccli2、磁盘 perccli /c0 show all3、raid卡 cc perccli /c0 show cc 4、raid卡 pr perccli /c0 show patrolread

安卓手机忘记锁屏密码怎么办?2个方法拯救你的解锁困境!

为了保护手机信息不被他人轻易获取&#xff0c;我们通常会设置锁屏密码。然而&#xff0c;记忆力有时也会捉弄人&#xff0c;即使是最常用的密码&#xff0c;也有可能因为一时的疏忽或遗忘而导致我们无法解锁自己的手机。安卓手机忘记锁屏密码怎么办&#xff1f;不必慌张&#…