我尝试将朋友名称注入与以下代码段一起使用:
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)方式来解决这个问题?
答案 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;
}
编译