【问题标题】:Issues with friend name injection朋友名字注入的问题
【发布时间】:2014-05-04 00:59:57
【问题描述】:

我试图让朋友姓名注入与以下 sn-p 一起工作:

struct foo
{
  friend foo f() { return {}; }
};

int main()
{
  auto x = f();
  return 0;
}

编译失败:

test.cc:8:10: error: use of undeclared identifier 'f'
  auto x = f();
           ^
1 error generated.

我必须在外部命名空间中声明 f 才能使错误消失。

该标准在 §7.3.1.2 的第 3 段中有解释:

如果一个朋友声明在一个 非本地类首先声明一个类、函数、类模板或函数模板97,友元是最内层封闭命名空间的成员。友元声明本身并不使名称对非限定查找 (3.4.1) 或限定查找 (3.4.3) 可见。 [注意:朋友的名字将在其命名空间中可见如果在命名空间范围内提供了匹配的声明(在授予友谊的类定义之前或之后)。 ——尾注]

我的问题:为什么我们需要在命名空间范围内额外声明 f 才能编译?跟ADL有关系吗?是否有解决此要求的(hacky)方法?

【问题讨论】:

  • 如果你可以强制ADL,那么它会找到f

标签: c++ friend


【解决方案1】:

您可以强制 ADL:

struct foo {
  friend foo f(foo *) { return {}; }
};

int main()
{
  auto x = f((foo *) 0);
  return 0;
}

使用 g++ 4.9.0 和 clang++ 3.4 编译。当然,可能不太实用。

附录:感谢 Richard Hodges,这是另一种可能的解决方法,但它可能是 g++ 4.9.0 的错误。 clang++ 和 g++ 是有区别的。如果我有时间,我会尝试研究标准的内容。如果 OP 想将此作为一个新问题发布,询问哪个编译器错误,请这样做。

struct foo {
  friend foo f1() { return {}; }
  friend foo f2(foo *) { return {}; }
  template<typename T = void>
  friend foo f3() { return {}; }
};

int main()
{
  auto x1 = f1(); // Error, f1() not visible.
  auto x2 = f2((foo *) 0); // Force ADL.
  auto x3 = f3<void>(); // Use template, okay with g++, fails with clang++.
  auto x4 = f3(); // Use template with default param, okay with g++, fails with clang++.
  return 0;
}

【讨论】:

  • struct foo { template 朋友 foo f() { return {}; } }; int main() { auto x = f();返回0; } 也可以编译 - 同样可怕。
  • 我想知道是否可以添加更多模板魔法以使f3 通用。
  • @MatthiasVallentin:不确定您是否看到带有默认模板参数的版本,因为我正在进行一些编辑。那个看起来像透明地工作,但可能是一个 g++ 错误。
  • 好的,快速搜索标准并没有找到任何东西。这似乎是一个 g++ 错误。所以问题是模板友元函数定义是否可用于在命名空间范围内没有匹配声明的查找。编译器不同意。如果您想要明确的答案,请将此作为新问题发布。
  • @MatthiasVallentin:这是新问题:stackoverflow.com/questions/23452015/…
【解决方案2】:

friend 致力于声明,而不是定义。

struct foo
{
  friend foo f();
};

foo f() { return {}; }

int main()
{
  auto x = f();
  return 0;
}

编译

【讨论】:

  • 你可以在朋友中定义一个函数。试试看。
  • 如果返回的类型是完整的。在上面定义 f() 的情况下, foo 不是一个完整的类型,所以它不能编译 f() (它构造了一个)。
  • 查看我发布的答案中的代码。它编译并运行。
  • 哦,很有趣……还有点破!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-07
  • 2015-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-10
相关资源
最近更新 更多