C++ 名称查找(Name lookup)与参数依赖查找ADL(Argument-dependent lookup)

这篇具有很好参考价值的文章主要介绍了C++ 名称查找(Name lookup)与参数依赖查找ADL(Argument-dependent lookup)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

名称查找中的几个概念

限定作用符 ::

限定名值指出现在::(限定作用符)右侧的名字,他可以是

  1. 命名空间
  2. 枚举

无限定作用域及,没有限定作用符在左侧的名字

有限定名查找,无限定名查找的一些规则

  1. 如果::限定作用符左侧留空,只会在全局命名空间查找;
  2. 存在多级限定作用符级联时,只有对左侧名查找完了,再在找到的作用域里对右侧进行查找;有限定和无限定和可以混用
  3. 对::左侧的符号进行查找,会忽略变量、函数、枚举项的声明
  4. 当在声明符中使用限定名,该声明符中的非限定名查找在限定名的类或者命名空间中查找
  5. 无限定查找,查找之前声明的部分,如果存在命名空间嵌套则会一级一级往外查找
  6. 友元声明的无限定名查找(非模板实参),先在友元的限定域里面查找,再在友元的声明所在域查找
  7. 模板非依赖名,立即绑定,并且模板的非限定名查找只可见模板定义点前的命名
  8. 如果某个基类取决于某个模板形参,那么无限定名字查找不会检查它的作用域
  9. 非限定名的ADL
struct A
{
    static int n;
};
int n = 1; // 声明
const int DD = 100;
class N{
    static const int DD = 50;
    static int S[DD];
     int m = 2;
 
    namespace Y
    {
        int x = n; // 规则5  找到 ::n
        int y = m; // 规则5,找到 ::N::m
    }
};
int N::S[DD]{};// 规则4,DD为N::DD,size 50

struct A
{
    typedef int AT;
 
    void f1(AT);
    void f2(float);
 
    template<class T>
    void f3();
 
    void f4(S<AT>);
};
 
// 这个类为 f1,f2 和 f3 授予友元关系
struct B
{
    typedef char AT;
    typedef float BT;
 
    friend void A::f1(AT);    // 规则6 对 AT 的查找找到的是 A::AT(在 A 中找到 AT)
    friend void A::f2(BT);    // 规则6 对 BT 的查找找到的是 B::BT(在 A 中找不到 AT)
    friend void A::f3<AT>();  // 规则6 对 AT 的查找找到的是 B::AT (不在 A 中进行查找,
                              //     因为 AT 在声明符中的标识符 A::f3<AT> 中)
};
 // 这个类模板为 f4 授予友元关系
template<class AT>
struct C
{
    friend void A::f4(S<AT>); //规则6 对 AT 的查找找到的是 A::AT 
                              // (AT 不在声明符中的标识符 A::f4 中)
};

void f(char); // f 的第一个声明
 
template<class T> 
void g(T t)
{
    f(1);    //  规则7 非待决名:名字查找找到了 ::f(char) 并在此时绑定
    f(t);    // 待决名:查找推迟
//  dd++;    // 非待决名:名字查找未找到声明
}
 
void f(int); // 模板不可见
double dd;
 
void h()
{
 
    g(32); // 实例化 g<int>,此处
           // 对 'f' 的第二次和第三次使用
           // 进行了查找仅找到了 ::f(char)
           // 然后重载解析选择了 ::f(char)
           // 这三次调用了 f(char),规则7 ,不可见f(int)
           
}

typedef double A;
 
template<class T>
class B
{
    typedef int A;
};
 
template<class T>
struct X : B<T>
{
    A a; //  规则8  对 A 的查找找到了 ::A (double),而不是 B<T>::A
};
 
int main()
{
	struct std {};
	::std::cout << "\n"; //  规则1,忽略std{}, 规则2 多级限定
    int A;
    A b;       //  查找,找到了变量 A,报错
    A::n = 42; // 规则3, A是无限定名,忽略变量A的定义,n是限定名
}

ADL

ADL拉出来单列,稍微特殊一点,相比非限定名的其他查找叫ordinary lookup(规则5逐层往外查找)
参数依赖查找,顾名思义,根据参数查找函数实现,是一种对无限定名的函数调用附加查找规则。

#include <iostream>
int main()
{
    std::cout << "测试\n"; // 全局命名空间中没有 operator<<,但 ADL 检验 std 命名空间,
                           // 因为左实参在 std 命名空间中
                           // 并找到 std::operator<<(std::ostream&, const char*)
    operator<<(std::cout, "测试\n"); // 同上,用函数调用记法
 
    // 然而,
    std::cout << endl; // 错误:'endl' 未在此命名空间中声明。
                       // 这不是对 endl() 的函数调用,所以不适用 ADL
 
    endl(std::cout); // OK:这是函数调用:ADL 检验 std 命名空间,
                     // 因为 endl 的实参在 std 中,并找到了 std::endl
 
    (endl)(std::cout); // 错误:'endl' 未在此命名空间声明。
                       // 子表达式 (endl) 不是函数调用表达式
}

因为规则7的缘由,没有ADL,模板的适用范围会极大受限(其实ADL用的最多的还是模板,具体实际使用案例可参照nlohmann json 库,其中大量使用的to_json 和 from_json 函数,原理就是ADL,通过ADL查找找到对应的用户自定义实现的序列反序列函数。)

template<typename T>
T max (T a, T b) {
    return b < a ? a : b;
}

namespace BigMath {
  class BigNumber {
    ...
};

  bool operator < (BigNumber const&, BigNumber const&);  //对模板 MAX 不可见,若无ADL
  ...
}

using BigMath::BigNumber;

void g (BigNumber const& a, BigNumber const& b) {
  ...
  BigNumber x = ::max(a,b);
  ...
}

忽略ADL的几种情况

如果未限定名查找所产生的候选集存在下述情形,则不会启动依赖于实参的名字查找:文章来源地址https://www.toymoban.com/news/detail-648559.html

  1. 成员函数声明
class MyClass {
public:
    void foo(int) {
        // 不考虑参数类型的命名空间,直接在类的作用域中查找
        std::cout << "MyClass::foo" << std::endl;
    }
};

int main() {
    NS1::A a;
    MyClass obj;
    
    obj.foo(a); // 不会触发ADL,直接在 MyClass 的作用域中查找 foo
}

  1. 块作用域中的函数声明(非using-declaration)
namespace NS1 {
    void foo() {
        std::cout << "NS1::foo" << std::endl;
    }
}

int main() {
    void foo(); // 在 main 函数作用域内声明一个函数

    foo(); // 不会触发ADL,直接在 main 函数作用域内查找 foo
}

  1. 非函数、函数模板的声明
namespace NS1 {
    struct MyStruct {
        void operator()() {
            std::cout << "MyStruct operator()" << std::endl;
        }
    };
}

int main() {
    NS1::MyStruct foo; // 函数对象

    foo(); // 不会触发ADL,直接在当前作用域内查找 foo
}

到了这里,关于C++ 名称查找(Name lookup)与参数依赖查找ADL(Argument-dependent lookup)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 名称服务器(Name Server)介绍

       名称服务器 (Name Server)是互联网域名系统(DNS)中的一部分,它们负责将用户可读的域名(例如:www.example.com)解析为计算机可识别的IP地址(例如:192.168.1.1)。这使得我们可以使用容易记忆的域名访问网站,而不是需要记住复杂数字的IP地址。   名称服务器通常

    2024年01月24日
    浏览(36)
  • 织梦cms图集{dede:field name='imgurls'显示栏目名称

    今天又接了个织梦cms的有偿服务,客户的网站是织梦图片站,所以内容页是用的图集。 他想在图片的alt上面显示栏目名称,默认的是没有这样的标签的 织梦图集默认标签主要就是一个[field:alttext /] 一个 [field:imgsrc/]. 图集标签是用的这个 {dede:field name=\\\'imgurls\\\' ,那么在图片alt怎么加上

    2024年02月02日
    浏览(50)
  • Git如何修改提交(commit)用户名称(user.name)和邮箱(user.email)

    Git查看用户名 修改Git提交用户名 如果出现以下错误,解决方案如下: 错误案例: 解决方案: 原因: 如果你去查看配置文件,你则会发现如下场景: Git查看邮箱 修改Git邮箱

    2024年02月04日
    浏览(53)
  • Unity 之 GameObject.Find()在场景中查找指定名称的游戏对象

    GameObject.Find 是 Unity 中的一个函数,用于在场景中查找指定名称的游戏对象。这个函数的主要作用是根据游戏对象的名称来查找并返回一个引用,使您能够在代码中操作该对象。以下是有关 GameObject.Find 的详细介绍: 函数签名: 使用方法: 您可以通过将游戏对象的名称作为参

    2024年02月10日
    浏览(37)
  • Django中使用反向关系名称(related_name)解决由“多对多”关系引起的字段名字冲突问题引起的迁移命令报错。

    当在模型中为关系字段添加了 related_name 参数后,您可以使用该参数指定的名称来引用反向关系。下面是一个简单的例子来说明如何引用反向关系。 假设您有以下两个模型: 在上面的例子中, Book 模型有一个外键字段 author ,它关联到 Author 模型。通过添加 related_name=\\\'books\\\' 参

    2024年02月16日
    浏览(46)
  • maven查找依赖的方法

    maven查找依赖的地址http://www.mvnrepository.com/ mvnrepository也是一个非常有用的maven仓库搜索服务,它最大的特点就是简单,除了搜索什么都没有。类似的,你可以在页面最上方输入以进行搜索。得到结果之后再点击以查看详细信息:该构件的坐标POM片段,版本信息,jar下载

    2024年02月15日
    浏览(255)
  • 如何查找Dll依赖

    使用ILSpy,可以在VS中查找到 1、打开ILSpy后程序集下全选,然后选择移除 2、把需要测试的dll拖入到程序集窗口下 3、依赖dll查询 1)除了该dll,程序集下其他dll即为依赖的dll 2)点击自己的dll,在其子项中有引用一项即为依赖的dll 3)也可以点击代码,查看其using中包含的程序

    2024年02月11日
    浏览(43)
  • 【技巧】Maven重复依赖分析查找

    【技巧】Maven重复依赖分析查找 遇到奇葩的错误可以考虑是不是依赖冲突了 比如同一段代码 再这个项目中好好的  另一个项目中不能用等 idea安装插件 打开pom文件 输入要查找的依赖   将不用的排除掉 右键排除即可  

    2024年02月17日
    浏览(70)
  • Maven 官网查找依赖包

    1、登录 Maven 官网地址 官网地址: https://mvnrepository.com/ 2、输入你要查找的 jar 包的相关信息(这里以 spring 为例) 3、双击 spring-context 跳转到如下界面,选中你需要的版本(这里以 spring-context 5.2.8.RELEASE 为例) 4、点击 5.2.8.RELEASE 这个版本,进入如下界面,可以看到直接可以复制对应的

    2024年02月16日
    浏览(34)
  • idea查找maven所有依赖

    缺点是只有依赖,没有版本 settings–plugins–搜索maven helper并安装 安装后打开pom.xml文件会有依赖解析 勾选conflict就是有冲突的依赖 选中all dependencies as list则所有依赖一列展示 选中all dependencies as tree 则所有依赖树形展示 缺点,如果是多模块项目,则必须一个一个pom.xml文件的

    2024年02月11日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包