删除函数和 ADL

Posted

技术标签:

【中文标题】删除函数和 ADL【英文标题】:Deleted function and ADL 【发布时间】:2017-09-20 06:26:05 【问题描述】:

我遇到了以下涉及 ADL 和删除函数的令人困惑的示例:

第一个例子:

namespace A

    struct S;

    void f(S)cout << "adl" << endl;


namespace C

    //void f() = delete;

    //void f (double);

    void test()
    
        A::S arg;
        f(arg);
    



int main()

    C::test();

    return 0;

正如所料,A::f 是通过 ADL 调用的。在下一个示例中,C 中有一个同名的已删除函数:

namespace A

    struct S;

    void f(S)cout << "adl" << endl;


namespace C

    void f() = delete;

    //void f (double);

    void testi()
    
        A::S arg;
        f(arg);
    



int main()

    C::testi();

    return 0;

编译失败并显示错误消息error: use of deleted function 'void C::f()'。显然,删除的函数阻止了 ADL 版本进入重载表。现在来看最后一个示例:除了已删除的函数之外,现在还有另一个未删除的同名函数:

namespace A

    struct S;

    void f(S)cout << "adl" << endl;


namespace C

    void f() = delete;

    void f (double);

    void testi()
    
        A::S arg;
        f(arg);
    



int main()

    C::testi();

    return 0;

运行它会执行f 的ADL 版本。所以总结:

当前命名空间没有匹配的函数会导致调用 ADL 版本 在当前命名空间中仅包含已删除的函数会导致错误,可能是因为根本没有发现 ADL 版本 在当前命名空间中有另一个未删除的函数会导致调用 ADL 版本。

我的问题:这种行为是故意的吗?如果是这样,标准的哪一部分规定了这一点?

编辑:忘了说我是用onlinegdb编译的,所以用了gcc/g++。

【问题讨论】:

【参考方案1】:

确定的编译器错误。引用C++标准草案(n4659)[dcl.fct.def.delete]/2:

隐式或显式引用已删除函数的程序, 除了声明它之外,它是不正确的。 [ 注意:这包括调用 函数隐式或显式并形成指针或 指向函数的成员指针。它甚至适用于 未进行潜在评估的表达式。 如果一个函数是 重载,仅当函数被选择时才被引用 重载决议。虚函数的隐式 odr 使用确实 本身并不构成参考。 — 尾注 ]

重载解决方案无法通过 ADL 选择该重载。所以这个函数不应该被引用。第二个代码示例是一个格式良好的 C++ 程序(如果重新放入缺少的包含指令)。


你提到使用g++编译,注意这个issue是fixed in GCC 7.2.0

【讨论】:

我刚刚意识到我的例子中使用了g++ 5.4.1 c++14 @LcdDrm - 如果您愿意,您可以使用Wandbox 并按 GCC 版本进行二进制搜索以准确了解修复的时间:) GCC 6.3 失败,GCC 7.1 有效。 MS Visual Studio 编译器也可以工作

以上是关于删除函数和 ADL的主要内容,如果未能解决你的问题,请参考以下文章

在除 ADL、“本地”或全局命名空间之外的命名空间中定义函数

诊断 ADL 崩溃?

[架构之路-110]-《软考-系统架构设计师》-软件架构设计-3-架构描述语言ADL与UML

ADL100-Wuwei-检索式对话

我应该如何制作功能咖喱?

IMAP 解析地址中的 ADL 字段是啥?