代码
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 用作友元声明的类型,则会出现上述错误,但有一个异常(exception)。当 typedef 不出现在 A 中但出现在 B 中时。 如果您删除模板,它也会构建。
感谢您的任何见解!
最佳答案
这大概是 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
,::
。 Clang 做了 A::X
、A
、::
、B::Y
、B
,::
。 gcc 执行了 A::X
、B::Y
、A
、::
。
现在,标准的查找顺序与我们在 Y
的上下文中一样:
for a friend declaration in a class
Y
, in a scope that would be searched for a name appearing withinY
.
即 B::Y
、B
、::
我们从不考虑 A
。换句话说,对于您的原始示例,将找到(根据需要)B::handle
,而不是 A::handle
。
关于c++ - 相同类型重新定义的 Clang typedef(和别名)导致意外错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51849707/