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

时间:2012-07-23 19:25:30

标签: c++ templates gcc clang argument-dependent-lookup

我有一个模板类NB::B<T>,它来自命名空间中的非模板类NA::Aact<T>是一个模板函数,在其模板参数的实例上调用add_ref函数。具体来说,act<NB::B<int>>希望使用ADL在add_ref的基础名称中找到NB::B。完整的示例如下:

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>();
}

这在gcc(4.7.0)中编译正常。在Comeau在线。但是clang(3.1)失败了:

a.cpp:4:3: error: use of undeclared identifier 'add_ref'

与此同时,该标准为:

  

3.4.2 / 2 ......

     

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

令人惊讶的是,模板的基础未列为关联命名空间的路径。因此clang的行为似乎是正确的。 Comeaugcc正在接受错误的计划。

同时,3.4.2/3声明参数名称空间中的using无效:

  

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

     

- 忽略相关命名空间中的任何using-directive。

但是当我取消注释using NA::add_refclang很高兴编译测试时。

为了将我的示例置于实践的角度,您可以认为actboost::intrusive_ptr的方法,add_ref(A*)intrusive_ptr_add_ref(CBase*)B是一些模板,源自基地CBase

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

  1. 我是对的,clang是否正确拒绝我的测试计划,gccComeau不符合标准?

  2. 标准是否指定了这种不切实际的行为(禁止将模板类库作为关联的命名空间)?

  3. clang错误接受using NA::add_ref指令的3.4.2/3错误接受我的测试程序?

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

  5. P.S。我看过clang Language Compatibility FAQ并没有在那里找到答案。

1 个答案:

答案 0 :(得分:6)

从n3337开始,基本上是C ++ 11,只有很少的编辑修改,3.4.2 / 2读取:

  

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

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

然后继续使用您在问题中发布的相同报价。这里的重要区别是此外,这意味着您引用的列表(我省略了)是对已经提到的名称空间的补充,其中包括基类所属的名称空间

  1. Gcc和comeau是对的,clang ++拒绝代码是错误的。

  2. &LT;不适用&gt;

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

  4. 是的,你应该报告一个错误。它似乎已经被报告并修复了。