c++ - 删除的函数和 ADL

标签 c++ overloading argument-dependent-lookup

我遇到了以下涉及 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++。

最佳答案

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

A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed. [ Note: This includes calling the function implicitly or explicitly and forming a pointer or pointer-to-member to the function. It applies even for references in expressions that are not potentially-evaluated. If a function is overloaded, it is referenced only if the function is selected by overload resolution. The implicit odr-use of a virtual function does not, by itself, constitute a reference.  — end note ]

重载解析无法通过 ADL 选择该重载。所以这个函数不应该被引用。第二个代码示例是一个格式良好的 C++ 程序(如果丢失的包含指令被放回原处)。


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

关于c++ - 删除的函数和 ADL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46314709/

相关文章:

c++ - 在依赖于参数的查找(或解决方法?)之前发生模板替换的任何方式

c++ - 在 Windows 中无法从 cmake 中找到 MySQL 和 Boost includes/libs

c# - 如何将可选指针参数从 C++ 代码转换为 C#

java - 重载 Java 类构造函数

perl - 我可以重载 Perl 的 = 吗? (还有使用 Tie 时的问题)

c++ - 重载运算符时可以使用标志吗?

c++ - ADL 是调用 friend 内联函数的唯一方法吗?

c++ - 无法输出到 C++ 中的二进制文件

c++ - 类成员函数与速度方面的函数

c++ - 根据非成员 swap() 实现成员 swap()