相同类型重新定义的 Clang typedef(和别名)导致意外错误
Clang typedef (and alias) of same type redefinition causes unexpected error
密码
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 not 存在于 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 within Y
.
即B::Y
、B
、::
而我们从来不考虑A
。换句话说,对于您的原始示例,将找到 B::handle
(根据需要),而不是 A::handle
.
密码
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 not 存在于 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
.