前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >现代C++之ADL

现代C++之ADL

作者头像
公众号guangcity
发布2020-01-14 16:23:27
1.5K0
发布2020-01-14 16:23:27
举报
文章被收录于专栏:光城(guangcity)光城(guangcity)

什么是“依赖于参数的查询”(又名ADL或“ Koenig查找”)?

Koenig查找或参数依赖查找描述了C ++编译器如何查找不合格的名称 。简单来说:如果在函数的名称空间中定义了一种或多种参数类型,则不必为函数限定名称空间。

例如:

代码语言:javascript
复制
namespace MyNamespace
{
    class MyClass {};
    void doSomething(MyClass);
}

MyNamespace::MyClass obj; // global object


int main()
{
    doSomething(obj); // Works Fine - MyNamespace::doSomething() is called.
}

在上面的示例中,既没有使用using声明也没有使用using指令,但是编译器仍然可以通过应用Koenig查找将正确的不合格名称doSomething()识别为在名称空间MyNamespace中声明的函数。

它是如何工作的?

该算法告诉编译器不仅要查看本地作用域,还要查看包含参数类型的名称空间。因此,在上面的代码中,编译器发现对象obj(它是函数doSomething()的参数)属于命名空间MyNamespace。因此,它将查看该命名空间以找到doSomething()的声明。

Koenig查找的优点是什么?

如上面的简单代码示例所示,Koenig查找为程序员提供了便利和易用性。如果没有Koenig查找,那么程序员将不得不负担重复指定完全限定名称的费用,或者使用大量using声明。

为什么批评Koenig查找?

过度依赖Koenig查找会导致语义问题,有时会使程序员措手不及。

考虑std :: swap的示例,它是交换两个值的标准库算法。使用Koenig查找时,使用此算法时必须谨慎,因为:

代码语言:javascript
复制
std::swap(obj1,obj2);

可能不会显示以下行为:

代码语言:javascript
复制
using std::swap;
swap(obj1, obj2);

使用ADL,调用哪个版本的交换函数将取决于传递给它的参数的名称空间。

如果存在命名空间A,并且存在A::obj1,A::obj2A::swap(),则第二个示例将导致对A::swap()的调用,这可能不是用户想要的。

此外,如果由于某种原因同时定义了A::swap(A :: MyClass&,A :: MyClass&)std::swap(A::MyClass&,A::MyClass&),则第一个示例将调用std::swap(A::MyClass&,A::MyClass&),但是第二个将无法编译,因为swap(obj1, obj2);会模棱两可。

上述完整例子如下:

代码语言:javascript
复制
#include <iostream>

namespace A {
    template<typename T>
    class smart_ptr {
    public:
        smart_ptr() noexcept : ptr_(nullptr) {

        }

        smart_ptr(const T &ptr) noexcept : ptr_(new T(ptr)) {

        }

        smart_ptr(smart_ptr &rhs) noexcept {
            ptr_ = rhs.release();       // 释放所有权,此时rhs的ptr_指针为nullptr
        }

        smart_ptr &operator=(smart_ptr rhs) noexcept {
            swap(rhs);
            return *this;
        }

        void swap(smart_ptr &rhs) noexcept { // noexcept == throw() 保证不抛出异常
            using std::swap;
            swap(ptr_, rhs.ptr_);
        }

        T *release() noexcept {
            T *ptr = ptr_;
            ptr_ = nullptr;
            return ptr;
        }

        T *get() const noexcept {
            return ptr_;
        }

    private:
        T *ptr_;
    };

// 提供一个非成员swap函数for ADL(Argument Dependent Lookup)
    template<typename T>
    void swap(A::smart_ptr<T> &lhs, A::smart_ptr<T> &rhs) noexcept {
        lhs.swap(rhs);
    }
}

// 开启这个注释,会引发ADL冲突
//namespace std {
//    // 提供一个非成员swap函数for ADL(Argument Dependent Lookup)
//    template<typename T>
//    void swap(A::smart_ptr<T> &lhs, A::smart_ptr<T> &rhs) noexcept {
//        lhs.swap(rhs);
//    }
//
//}

int main() {

    using std::swap;
    A::smart_ptr<std::string> s1("hello"), s2("world");
    // 交换前
    std::cout << *s1.get() << " " << *s2.get() << std::endl;
    swap(s1, s2);      // 这里swap 能够通过Koenig搜索或者说ADL根据s1与s2的命名空间来查找swap函数
    // 交换后
    std::cout << *s1.get() << " " << *s2.get() << std::endl;
}

本篇学习自: https://stackoverflow.com/questions/8111677/what-is-argument-dependent-lookup-aka-adl-or-koenig-lookup

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-12-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 光城 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是“依赖于参数的查询”(又名ADL或“ Koenig查找”)?
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档