【问题标题】:Argument-dependent lookup through base of a template class通过模板类的基础进行依赖于参数的查找
【发布时间】:2012-07-22 01:52:10
【问题描述】:

我有一个模板类 NB::B<T> 派生自命名空间中的非模板类 NA::Aact<T> 是一个模板函数,在其模板参数的实例上调用 add_ref 函数。具体来说,act<NB::B<int>> 想要使用 ADL 查找定义在 NB::B 的基础命名空间中的 add_ref。完整的例子如下:

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 指令都将被忽略。

但是当我取消注释 using NA::add_ref 行时,clang 很乐意编译测试。

从实际的角度来看我的例子,你可以认为actboost::intrusive_ptr 的方法,add_ref(A*)intrusive_ptr_add_ref(CBase*)B 是一些模板,派生自基础CBase

对此我有几个问题:

  1. clang 拒绝我的测试程序是正确的,gccComeau 不符合标准吗?

  2. 标准指定这种不切实际的行为(不允许模板类基作为关联的命名空间)是否有原因?

  3. clang 是否以 3.4.2/3 为由错误地接受我的带有 using NA::add_ref 指令的测试程序?

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

附:我已阅读 clang Language Compatibility FAQ 并没有在那里找到答案。

【问题讨论】:

  • C++11 模式有帮助吗? C++11 似乎已经澄清了措辞,因为实际上NB::B&lt;int&gt; 是一个类(恰好是模板特化),而不是模板。 (IIUC 的规则是,与模板相关联的命名空间被添加到与类相关联的命名空间中。)
  • 这不是很脆弱吗?在某些时候,您可能会添加 add_ref 的默认实现,它总是比直接基的关联命名空间更好?
  • @LucDanton,你是对的。这两点(关于classtemplate-id 的关联命名空间)都适用于template-id 类。
  • @pmr,这确实有点脆弱。虽然我不明白你的评论。没有 ADL,什么都找不到,因为在来自 intrusive_ptr.hpp 的调用范围内没有 add_ref 函数。
  • @NichtVerstehen 对于默认实现,我的意思是:除非在 act 函数的范围内有函数 add_refact() 命名空间中的模板可以更好地匹配,并且会被选择而不是与 base 关联的函数。

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


【解决方案1】:

从基本上是 C++11 的 n3337 开始,只有少量编辑更改,3.4.2/2 内容如下:

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

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

然后它继续使用您在问题中发布的基本相同的引用。这里的重要区别是进一步,这意味着您引用的列表(我省略了)是除了已经提到的命名空间之外,还包括基类所属的命名空间.

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

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

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

【讨论】:

  • 该错误已在一段时间前报告并已修复。 zhr 错误是 thag clang 没有使用模板来查找它的基类(及其友元声明)
  • 谢谢,@david-rodriguez-dribeas。那个“进一步”澄清了这个问题。
  • @johannes-schaub-litb,您有没有机会记得指向您正在谈论的错误的链接?我刚刚在 clang 主干的新版本上检查了这一点,并且该错误仍然存​​在。
猜你喜欢
  • 2016-03-24
  • 1970-01-01
  • 1970-01-01
  • 2022-01-14
  • 1970-01-01
  • 2010-09-05
  • 2018-04-02
  • 1970-01-01
相关资源
最近更新 更多