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

时间:2018-08-14 21:01:13

标签: c++ c++11 templates clang++

代码

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中。 如果您删除模板,它也会生成。

感谢您的见解!

1 个答案:

答案 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::XB::YB::。 lang做了A::XA::B::YB::。 gcc做了A::XB::YA::

现在,标准的查找顺序与在Y上下文中的查找顺序相同:

  

在某个类Y中的朋友声明中,该范围要在搜索范围内搜索出现在Y中的名称。

B::YB::,我们从不考虑A。换句话说,对于您的原始示例,将(根据需要)找到B::handle,而不是A::handle