已删除功能和ADL

时间:2017-09-20 06:26:05

标签: 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 ++。

1 个答案:

答案 0 :(得分:1)

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

  

隐式或明确引用已删除函数的程序,   除了宣布它之外,是不正确的。 [注意:这包括打电话   函数隐式或显式并形成指针或   指向函数的指针成员。它甚至适用于参考   没有潜在评估的表达式。 如果有功能的话   重载时,仅在选择函数时才引用它   重载决议。虚函数的隐式odr使用确实如此   本身并不构成参考。 - 结束说明]

过载分辨率无法通过ADL选择过载。所以不应该引用这个功能。第二个代码示例是一个格式良好的C ++程序(如果丢失的include指令被放回)。

您提到使用g ++进行编译,请注意此问题为fixed in GCC 7.2.0