简体   繁体   English

相同类型重定义的 Clang typedef(和别名)导致意外错误

[英]Clang typedef (and alias) of same type redefinition causes unexpected error

The code编码

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
}

The 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.

The problem问题

I was trying to get my company's code to build under clang, and ran across this scenario.我试图让我公司的代码在 clang 下构建,并遇到了这种情况。 The code builds under GCC 5 - 8. I've tried to find a rule that describes this scenario, but have come up empty.代码在 GCC 5 - 8 下构建。我试图找到描述这种情况的规则,但结果是空的。 The fix (or workaround) is obvious, but I'm seeking clarification of what is going on to better understand the scenario.修复(或解决方法)是显而易见的,但我正在寻求澄清正在发生的事情以更好地理解场景。

So both classes define the same typedef (also tried with aliases, same result) as the same type.因此,两个类都定义了相同的 typedef(也尝试使用别名,结果相同)作为相同的类型。 If the typedef is used as the type for the friend declaration, it gives the error above, with one exception.如果 typedef 用作友元声明的类型,则会出现上述错误,只有一个例外。 When the typedef is not present in A but is in B. It will also build if you strip out the templates.当 typedef不在A 中但在 B 中时。如果您去掉模板,它也会构建。

Thanks for any insights!感谢您的任何见解!

This is roughly CWG 1906 .这大致是CWG 1906 Basically, clang implemented the actual wording in the standard - which didn't make much sense.基本上,clang 实施了标准中的实际措辞 - 这没有多大意义。

Basically, consider this example, courtesy of Richard Smith:基本上,考虑一下这个例子,由 Richard Smith 提供:

namespace A { 
  struct X { void f(int); }; 
} 
namespace B { 
  using type = int; 
  struct Y { 
    friend void A::X::f(type);
  }; 
} 

The standard's lookup order for type used to be A::X , B::Y , B , :: .标准的type查找顺序曾经是A::XB::YB:: Clang did A::X , A , :: , B::Y , B , :: . Clang 做了A::X , A , :: , B::Y , B , :: gcc did A::X , B::Y , A , :: . gcc 做了A::XB::YA::

Now, the standard's lookup order is the same as if we were in the context of Y :现在,标准的查找顺序与我们在Y的上下文中相同:

for a friend declaration in a class Y , in a scope that would be searched for a name appearing within Y .对于类Y的朋友声明,在将搜索出现在Y的名称的范围内。

That is, B::Y , B , :: and we never consider A .也就是说, B::YB::并且我们从不考虑A In other words, for your original example, B::handle would be found (as desired), rather than A::handle .换句话说,对于您的原始示例,将找到B::handle (根据需要),而不是A::handle

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM