template <typename T, typename Y>
class B;
template <typename T, typename Y>
class A {
public:
typedef B<T, Y> handle;
void func(B<T, Y> &arg);
};
template <typename T, typename Y>
class B {
public:
typedef B<T, Y> handle;
private:
int i;
public:
// friend void A<T,Y>::func(B<T, Y>& arg); //builds
friend void A<T, Y>::func(handle &arg); // builds with alias in A *not* defined, otherwise fails.
};
template <typename T, typename Y> void A<T, Y>::func(B<T, Y> &arg) {
arg.i = 9;
}
int main() {
B<int, int> b;
A<int, int> a;
a.func(b); // error
}
main.cpp:31:7: error: 'i' is a private member of 'B<int, int>'
arg.i = 9;
^
main.cpp:38:5: note: in instantiation of member function 'A<int, int>::func' requested here
a.func(b);
^
main.cpp:23:7: note: declared private here
int i;
^
1 error generated.
我试图让我的公司代码在clang下构建,并遇到了这种情况。该代码在GCC 5-8下构建。我试图找到一个描述这种情况的规则,但是没有内容。修复程序(或解决方法)很明显,但是我正在寻求澄清正在发生的事情,以便更好地理解这种情况。
因此,这两个类都将相同的typedef定义为相同的typedef(也尝试使用别名和相同的结果)。如果将typedef用作friend声明的类型,则它会给出上面的错误,但有一个例外。当typedef在A中不存在时,但在B中。 如果您删除模板,它也会生成。
感谢您的见解!
答案 0 :(得分:1)
这大约是CWG 1906。基本上,clang在标准中实现了实际的措词-这没有多大意义。
基本上,考虑这个例子,由理查德·史密斯(Richard Smith)提供:
namespace A {
struct X { void f(int); };
}
namespace B {
using type = int;
struct Y {
friend void A::X::f(type);
};
}
type
的标准查找顺序以前是A::X
,B::Y
,B
,::
。 lang做了A::X
,A
,::
,B::Y
,B
,::
。 gcc做了A::X
,B::Y
,A
,::
。
现在,标准的查找顺序与在Y
上下文中的查找顺序相同:
在某个类
Y
中的朋友声明中,该范围要在搜索范围内搜索出现在Y
中的名称。
即B::Y
,B
,::
,我们从不考虑A
。换句话说,对于您的原始示例,将(根据需要)找到B::handle
,而不是A::handle
。