朋友姓名注入的问题

时间:2014-05-04 00:59:57

标签: c++ friend

我尝试将朋友名称注入与以下代码段一起使用:

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. friend是最内层封闭命名空间的成员。友元声明本身不会使名称对非限定查找(3.4.1)或限定查找(3.4.3)可见。 [注意:如果在命名空间范围内(在授予友谊的类定义之前或之后)提供匹配的声明,则朋友的名称将在其命名空间中可见。。 - 结束说明]

我的问题:为什么我们需要在命名空间范围内额外声明f以进行编译?它与ADL有关吗?是否有(hacky)方式来解决这个问题?

2 个答案:

答案 0 :(得分:2)

您可以强制ADL:

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

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

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

ADDENDUM:感谢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;
}

答案 1 :(得分:-1)

朋友在宣言上工作,而不是定义。

struct foo
{
  friend foo f();
};

foo f() { return {}; }

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

编译