ADL是调用朋友内联函数的唯一方法吗?

YSC*_*YSC 24 c++ friend language-lawyer name-lookup argument-dependent-lookup

让我们在声明中定义f:作为朋友的函数:SS

struct S
{
    friend void f() {}
};
Run Code Online (Sandbox Code Playgroud)

我找不到打电话的方法f.

那么,这样的内联友元函数只能通过依赖参数的查找来调用吗?

struct S
{
    friend void f() {}
    friend void g(S const&) {}
} const s;

int main()
{
    // f();     // error: 'f' was not declared in this scope
    // S::f();  // error: 'f' is not a member of 'S'
    g(s);
    // S::g(s); // error: 'g' is not a member of 'S'
}
Run Code Online (Sandbox Code Playgroud)

额外奖励:如果我想获得函数指针/ std::function/ lambda g怎么办?

Sto*_*ica 11

那么,这样的内联友元函数只能通过依赖于参数的查找来调用吗?

是.如[namespace.memdef]/3中所指定:

如果friend非本地类中的声明首先声明类,函数,类模板或函数模板.friend是最里面的封闭命名空间的成员.友元声明本身不会使名称对非限定查找([basic.lookup.unqual])或限定查找([basic.lookup.qual])可见.

由于唯一的声明f是其内联定义,因此对于限定或不合格的查找不可见.但是,ADL对这些朋友函数有一个特殊的规定,[basic.lookup.argdep]/4:

在考虑关联的命名空间时,查找与关联命名空间用作限定符([namespace.qual])时执行的查找相同,除了:

  • 在关联类中声明的任何命名空间范围的朋友函数或友元函数模板在其各自的命名空间中是可见的,即使它们在普通查找期间不可见([class.friend]).

至于你的奖金问题,lambda应该这样做:

auto exposed_g = [](S const& s){ g(s); };
Run Code Online (Sandbox Code Playgroud)

它将ADL包裹在体内.虽然关于退货类型扣除的常见警告适用.它将是一个值(假设您不返回void).

  • @YSC - 之后也可以声明它.这里的意思是,如果它是唯一可用的声明,那么到目前为止它是不可见的. (4认同)

son*_*yao 8

该名称f友元声明中声明,即使它成为包含的命名空间的成员S,但它在名称查找时不可见,除非它在命名空间范围内重新声明.如果没有,它只能由ADL找到.

友元声明在非本地类中引入的名称X成为最内层封闭命名空间的成员X,但它们不会对普通名称查找可见(既不是非限定的也不是限定的),除非在命名空间范围内提供匹配声明,无论是在之前还是之后类定义.可以通过ADL找到这样的名称,ADL同时考虑名称空间和类.

  • @MartinBonner - 曾经有一个名为"朋友姓名注入"的东西.它被移除到第一个标准出版物.这是论文,理由包括http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1995/N0777.pdf (2认同)