C++ ADL参数依赖查找

自以为作为一个C++老鸟,对C++里面各种概念应该都比较熟悉了,但是今天看书的时候又学到了一个装逼的概念ADL,本着学C++装逼装到底的精神,就把这个概念学习了一番。

ADL 的工作原理

在C++中,ADLArgument-Dependent Lookup 的缩写即参数依赖查找。它是一种在特定情况下用来查找函数或运算符的规则。

ADL 会在调用函数时,除了按照通常的作用域规则查找函数外,还会根据函数参数的命名空间类类型来查找可能的候选函数。

当你调用一个未限定作用域的函数(例如没有写 namespace:: 的函数调用),编译器会:

  • 先在调用处的普通作用域中查找函数(即通过标准的名称查找规则)。
  • 如果未找到匹配的函数,编译器会根据参数类型的命名空间类所在的命名空间,继续查找函数。
  • 编译器会优先选择参数所在命名空间中的函数,而不是全局命名空间中的同名函数。
#include <iostream>

namespace MyNamespace {
    struct MyStruct {};

    void print(const MyStruct&) {
        std::cout << "MyNamespace::print called\n";
    }
}

int main() {
    MyNamespace::MyStruct obj;

    // 调用未限定作用域的函数
    print(obj); // ADL 会查找到 MyNamespace::print
    return 0;
}

在上面的例子中,虽然没有显式写出 MyNamespace::print(obj),但由于参数 objMyNamespace::MyStruct 类型,ADL 会将 MyNamespace 纳入函数查找范围,最终找到 MyNamespace::print

ADL 与运算符重载

其实在最常见的运算符重载中已经有ADL的使用,只不过之前不知道ADL这个概念而已,看下面例子是不是很熟悉

#include <iostream>

namespace Math {
    struct Vector {
        int x, y;
    };

    // 定义一个和全局 operator<< 不冲突的版本
    std::ostream& operator<<(std::ostream& os, const Vector& v) {
        os << "(" << v.x << ", " << v.y << ")";
        return os;
    }
}

int main() {
    Math::Vector v{3, 4};

    // ADL 确保 operator<< 从 Math 命名空间查找到正确的定义
    std::cout << v << std::endl;

    return 0;
}

std::ostream 重载的 << 流运算符是定义在标准命名空间 std 中的,上面函数本该调用 std::operator<<(std::cout, v),但是在 Math 命名空间中,用户重载了Math::Vectoroperator<< 定义,ADL 会自动找到正确的 Math::operator<<

运算符重载是 ADL 的一个经典应用场景,因为运算符通常与自定义类型的命名空间相关联,ADL 可以确保运算符能正确地从参数的相关命名空间中找到。

ADL 和 std::swap

std::swap 是 C++ 标准库中的一个函数模板,用于交换两个对象的值。为了支持自定义类型,可以在自定义类型的命名空间中重载 swap

#include <algorithm> // std::swap
#include <iostream>

namespace Custom {
    struct Widget {
    int value;
};

    // 定义命名空间范围的自定义 swap
    void swap(Widget& lhs, Widget& rhs) {
        std::swap(lhs.value, rhs.value); // 使用标准库的 swap 交换内部值
        std::cout << "Custom::swap called\n";
    }
}

int main() {
    Custom::Widget w1{10}, w2{20};

    // 调用 std::swap
    using std::swap;
    swap(w1, w2); // ADL 会查找到 Custom::swap

    std::cout << "w1.value = " << w1.value << ", w2.value = " << w2.value << "\n";

    return 0;
}

调用 swap(w1, w2) 时,标准库的 std::swap 不适合直接处理 Custom::Widget。ADL 将根据参数 w1w2 的类型,进入 Custom 命名空间,找到 Custom::swap

ADL 和隐藏友元函数

隐藏友元函数是指通过在类中定义友元函数,但将其声明和定义放在类的内部,而不是类的外部。这种方式使得友元函数无法直接在类外部被普通的名称查找规则找到,但它可以通过 ADL 被正确查找到。隐藏友元函数的作用通常是防止全局作用域污染,限制函数的可见性,使得函数仅在需要时通过 ADL 查找到。

#include <iostream>

class MyClass {
public:
    MyClass(int value) : value_(value) {}

    // 声明一个友元函数
    friend std::ostream& operator<<(std::ostream& os, const MyClass& obj) {
        os << "MyClass(" << obj.value_ << ")";
        return os;
    }

private:
    int value_;
};

int main() {
    MyClass obj(42);

    // ADL 会查找到友元函数 operator<<
    std::cout << obj << std::endl;

    // std::operator<< 不会因为友元函数的定义而被隐藏
    std::cout << "Test" << std::endl;
    return 0;
}
  • operator<< 是一个隐藏友元函数,因为它的声明和定义都在 MyClass 内部。
  • 当调用 std::cout << obj 时,ADL 会通过参数 obj 的类型(MyClass)进入 MyClass 的定义范围,并找到 operator<<
总结

上面的一些示例代码其实是日常中比较常见的稀疏平常的代码,但是之前基本上不知道里面还有ADL这一说法,相信大家了解ADL概念了,应该对之前一些稀松平常的代码有更深的理解。

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

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

相关文章

MATLAB矩阵元素的修改及删除

利用等号赋值来进行修改 A ( m , n ) c A(m,n)c A(m,n)c将将矩阵第 m m m行第 n n n列的元素改为 c c c&#xff0c;如果 m m m或 n n n超出原来的行或列&#xff0c;则会自动补充行或列&#xff0c;目标元素改为要求的&#xff0c;其余为 0 0 0 A ( m ) c A(m)c A(m)c将索引…

告别 Kafka,拥抱 Databend:构建高效低成本的用户行为分析体系

用户行为数据埋点指标是数据仓库中不可或缺的重要数据源之一&#xff0c;同时也是企业最宝贵的资产之一。通常情况下&#xff0c;用户行为数据分析包含两大数据源&#xff1a;用户行为分析日志和上游关系型数据库&#xff08;如 MySQL&#xff09;。基于这些数据&#xff0c;企…

WEB攻防-通用漏洞文件上传中间件解析漏洞编辑器安全

中间件文件解析-IIS&Apache&Nginx Web应用编辑器-Ueditor文件上传安全 实例CMS&平台-中间件解析&编辑器引用 Vulhub是一个基于docker和docker-compose的漏洞环境集合&#xff0c;进入对应目录并执行一条语句即可启动一个全新的漏洞环境&#xff0c;让漏洞复现…

【算法day1】数组:双指针算法

题目引用 这里以 1、LeetCode704.二分查找 2、LeetCode27.移除元素 3、LeetCode977.有序数组的平方 这三道题举例来说明数组中双指针的妙用。 1、二分查找 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜…

快速理解微服务中Sentinel怎么实现限流

Sentinel是通过动态管理限流规则&#xff0c;根据定义的规则对请求进行限流控制。 一.实现步骤 1.定义资源&#xff1a;在Sentinel中&#xff0c;资源可以是URL、方法等&#xff0c;用于标识需要进行限流的请求&#xff1b;(在Sentinel中&#xff0c;需要我们去告诉Sentinel哪些…

controller中的参数注解@Param @RequestParam和@RequestBody的不同

现在controller中有个方法&#xff1a;&#xff08;LoginUserRequest是一个用户类对象&#xff09; PostMapping("/test/phone")public Result validPhone(LoginUserRequest loginUserRequest) {return Result.success(loginUserRequest);}现在讨论Param("login…

OpenCV截取指定图片区域

import cv2 img cv2.imread(F:/2024/Python/demo1/test1/man.jpg) cv2.imshow(Image, img) # 显示图片 #cv2.waitKey(0) # 等待按键x, y, w, h 500, 100, 200, 200 # 示例坐标 roi img[y:yh, x:xw] # 截取指定区域 cv2.imshow(ROI, roi) cv2.waitKey(0) cv…

【经典】星空主题的注册界面HTML,CSS,JS

目录 界面展示 完整代码 说明&#xff1a; 这是一个简单的星空主题的注册界面&#xff0c;使用了 HTML 和 CSS 来实现一个背景为星空效果的注册页面。 界面展示 完整代码 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8&…

后端:事务

文章目录 1. 事务2. Spring 单独配置DataSource3. 利用JdbcTemplate操作数据库4. 利用JdbcTemplate查询数据5. Spring 声明式事务6. 事务的隔离级别6.1 脏读6.2 不可重复读6.3 幻读6.4 不可重复读和幻读的区别6.5 三种方案的比较 7. 事务的传播特性8. 设置事务 只读(readOnly)9…

vue element-ui的el-image 和 el-table冲突层级冲突问题问题preview-teleported

问题: 解决代码:preview-teleported <el-image style"width: 50px; height: 50px" :src"props.row.url" :zoom-rate"1.2" :max-scale"7":min-scale"0.2" :preview-src-list"[props.row.url]" :initial-index&…

vue3 开发利器——unplugin-auto-import

这玩意儿是干啥的&#xff1f; 还记得 Vue 3 的组合式 API 语法吗&#xff1f;如果有印象&#xff0c;那你肯定对以下代码有着刻入 DNA 般的熟悉&#xff1a; 刚开始写觉得没什么&#xff0c;但是后来渐渐发现&#xff0c;这玩意儿几乎每个页面都有啊&#xff01; 每次都要写…

FreeSWITCH 简单图形化界面34 - 网络环境安全的情况下,进行任意SIP注册

FreeSWITCH 简单图形化界面34 -网络环境安全的情况下&#xff0c;进行任意SIP注册 测试环境1、前言2、参数3、实践一下 测试环境 http://myfs.f3322.net:8020/ 用户名&#xff1a;admin&#xff0c;密码&#xff1a;admin FreeSWITCH界面安装参考&#xff1a;https://blog.cs…

基于Matlab深度学习的CT影像识别系统研究与实现

通过使用AlexNet、GoogLeNet和VGGNet等预训练模型&#xff0c;并结合迁移学习技术&#xff0c;对CT影像进行特征提取和分类。系统在公开数据集上进行了训练和测试&#xff0c;结果表明&#xff0c;该方法能够有效区分COVID-19和非COVID-19的CT影像&#xff0c;具有较高的准确率…

如何使用postman做接口测试?

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 常用的接口测试工具主要有以下几种&#xff1a; Postman: 简单方便的接口调试工具&#xff0c;便于分享和协作。具有接口调试&#xff0c;接口集管理&#…

数据分析的尽头是web APP?

数据分析的尽头是web APP&#xff1f; 在做了一些数据分析的项目&#xff0c;也制作了一些数据分析相关的web APP之后&#xff0c;总结自己的一些想法和大家分享。 1.web APP是呈现数据分析结果的另外一种形式。 数据分析常见的结果是数据分析报告&#xff0c;可以是PPT或者…

学习笔记037——Java中【Synchronized锁】

文章目录 1、修饰方法1.1、静态方法&#xff0c;锁定的是类1.2、非静态方法&#xff0c;锁定的是方法的调用者&#xff08;对象&#xff09; 2、修饰代码块&#xff0c;锁定的是传入的对象2.1、没有锁之前&#xff1a;2.2、有锁后&#xff1a; 实现线程同步&#xff0c;让多个线…

开源加密库mbedtls及其Windows编译库

目录 1 项目简介 2 功能特性 3 性能优势 4 平台兼容性 5 应用场景 6 特点 7 Windows编译 8 编译静态库及其测试示例下载 1 项目简介 Mbed TLS是一个由ARM Maintained的开源项目&#xff0c;它提供了一个轻量级的加密库&#xff0c;适用于嵌入式系统和物联网设备。这个项…

QTableWidget使用代理绘制分行显示

在这里插入代码片# 创建主窗口类&#xff1a; 使用 QTableWidget 作为核心控件。 设置表头及行列信息。 自定义代理&#xff1a; 继承 QStyledItemDelegate&#xff0c;实现代理模式。 重写 paint 和 sizeHint 方法&#xff0c;支持多行文本绘制。 设置行高以适应多行显示。 …

Python学习35天

# 定义父类 class Computer: CPUNone MemoryNone diskNone def __init__(self,CPU,Memory,disk): self.disk disk self.Memory Memory self.CPU CPU def get_details(self): return f"CPU:{self.CPU}\tdisk:{self.disk}\t…

企业OA管理系统:Spring Boot技术深度解析

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…