依赖于参数的查找通过模板类的基础

Nic*_*hen 8 c++ gcc templates clang argument-dependent-lookup

我有一个NB::B<T>NA::A命名空间中的非模板类派生的模板类.act<T>是模板函数add_ref在其模板参数的实例上调用函数.具体来说,act<NB::B<int>>想要使用ADL 找到add_refNB::Bbase 的名称空间中定义的内容.完整的例子如下:

template<class T>
void act() {
  T* p = 0;
  add_ref(p); // the failing line
}

namespace NA
{
  struct A { };

  // I want ADL to find this:
  void add_ref(A* p) {
  }
}

namespace NB
{
  // template class with non-template base
  template <class T>
  struct B: NA::A { };

  typedef B<int> Bi;

  // using NA::add_ref; // fixes the problem
}

int main()
{
  act<NB::Bi>();
}
Run Code Online (Sandbox Code Playgroud)

这个编译好了gcc(4.7.0).在Comeau网上.但是clang(3.1)失败了:

a.cpp:4:3: error: use of undeclared identifier 'add_ref'
Run Code Online (Sandbox Code Playgroud)

同时,标准如下:

3.4.2/2 ......

- 如果T是template-id,则其关联的名称空间和类是定义模板的名称空间; 对于成员模板,成员模板的类; 与模板类型参数(模板模板参数除外)提供的模板参数类型相关联的名称空间和类; 定义任何模板模板参数的名称空间; 以及定义用作模板模板参数的任何成员模板的类.

令人惊讶的是,模板的基础未列为关联命名空间的路径.因此clang,这种行为似乎是正确的.而Comeaugcc正在接受不正确的程序.

同时,3.4.2/3规定using的在参数的命名空间没有任何效果:

在考虑关联的命名空间时,查找与关联命名空间用作限定符时执行的查找相同(3.4.3.2),但以下情况除外:

- 忽略关联命名空间中的任何using-directive.

但是,当我取消对using NA::add_ref线clang很高兴编译测试.

为了把我的例子转化为实际的角度来看,你可以认为这act是一个方法boost::intrusive_ptr,add_ref(A*)intrusive_ptr_add_ref(CBase*)B是一些模板,从基地获得CBase.

关于这一点,我有几个问题:

  1. 我是正确的clang的是正确的拒绝我的测试程序,gcc以及Comeau不按标准?

  2. 是否有理由为什么标准指定了这种不切实际的行为(不允许将模板类库作为关联的命名空间)?

  3. 是否clang接受我的测试程序与using NA::add_ref指令的理由是错误的3.4.2/3

  4. 我应该报告错误吗?:)

PS我已经阅读过clang语言兼容性常见问题解答,但在那里找不到答案.

Dav*_*eas 6

从n3337开始,基本上是C++ 11并进行了少量的编辑修改,3.4.2/2读取:

对于函数调用中的每个参数类型T [...]命名空间和类的集合按以下方式确定:[...]

  • 如果T是类类型(包括联合),则其关联的类是:类本身; 它所属的成员,如果有的话; 而其直接和间接基类.其关联的名称空间是其关联类是成员的名称空间.此外,如果T是一个类模板专业化,...

然后继续使用您在问题中发布的相同报价.这里最重要的区别是的,这意味着您引用(我省略)名单是除了已经提到的命名空间,以及包括命名空间,其基类是其成员.

  1. Gcc和comeau是正确的,而clang ++在拒绝代码时是错误的.

  2. <不适用>

  3. Clang ++在没有它的情况下拒绝它是错误的using NA::add_ref.

  4. 是的,您应该报告错误.似乎已经报道并修复了它.