【问题标题】:Is ADL the only way to call a friend inline function?ADL 是调用朋友内联函数的唯一方法吗?
【发布时间】:2018-07-12 11:31:39
【问题描述】:

让我们在S的声明中定义f,作为S的友元函数:

struct S
{
    friend void f() {}
};

我找不到联系f的方法。

那么,这样的内联友元函数真的只能用argument-dependant lookup调用吗?

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'
}

奖励:如果我想获得一个函数指针/std::function/lambda 到g,该怎么办?

【问题讨论】:

  • 请注意,如果您在S的定义之前声明(但未定义)f,则一切正常。

标签: c++ language-lawyer friend argument-dependent-lookup name-lookup


【解决方案1】:

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

是的。如[namespace.memdef]/3中所述:

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

由于fonly 声明是它的内联定义,因此它对合格或不合格的查找不可见。但是,ADL 对此类朋友功能有特殊规定,[basic.lookup.argdep]/4

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

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

至于你的额外问题,一个 lambda 应该可以做到:

auto exposed_g = [](S const& s){ g(s); };

它将 ADL 包装到它的主体中。尽管适用于返回类型扣除的常见警告。这将是一个值(假设您不返回 void)。

【讨论】:

  • "first 声明" 引起了我的兴趣。这是否意味着f 可见,必须在之前 声明它在S 中定义?如果是:coliru.stacked-crooked.com/a/a10f693434919727
  • @YSC - 也可以在之后声明。这里的意思是,如果它是在某一点之前唯一可用的声明,那么它在该点之前是不可见的。
【解决方案2】:

名称ffriend declaration 中声明,即使它成为包含Snamespace 的成员,但它对于名称查找不可见,除非它在命名空间范围内重新声明。如果没有,只有ADL才能找到。

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

【讨论】:

  • “除非在命名空间范围内提供匹配的声明” 会让我回答“否”。问题。 (或至少,“视情况而定”)
  • @MartinBonner - 曾经有一种叫做“朋友名字注入”的东西。它在第一个标准出版物中被删除。这是论文,其中包含理由open-std.org/jtc1/sc22/wg21/docs/papers/1995/N0777.pdf
【解决方案3】:

没有。你应该正确地声明函数。

struct S;
inline void f();
inline void g(S const&);

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

int main()
{
    f(); // Ok
    // S::f();  // error: 'f' is not a member of 'S'
    g(s);
    // S::g(s); // error: 'g' is not a member of 'S'
}

online compiler

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-27
    • 1970-01-01
    • 1970-01-01
    • 2013-05-21
    • 2017-09-11
    相关资源
    最近更新 更多