我有一个从命名空间中NB::B<T>
的非模板类派生的模板类NA::A
。是在其模板参数的实例上act<T>
调用函数的模板函数。add_ref
具体来说,act<NB::B<int>>
想使用 ADL查找add_ref
定义在 's base 的命名空间中。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 …</p>
— 如果 T 是模板 ID,则其关联的命名空间和类是定义模板的命名空间;对于成员模板,成员模板的类;与为模板类型参数(不包括模板模板参数)提供的模板参数的类型相关联的命名空间和类;定义任何模板模板参数的命名空间;以及定义用作模板模板参数的任何成员模板的类。
令人惊讶的是,模板的基础并未列为关联命名空间的路径。因此clang
的行为似乎是正确的。并且正在接受不正确的程序Comeau
。gcc
同时,参数命名空间中的 '3.4.2/3
声明using
无效:
在考虑关联命名空间时,查找与将关联命名空间用作限定符 (3.4.3.2) 时执行的查找相同,除了:
— 相关命名空间中的任何 using 指令都将被忽略。
但是当我取消注释时,该using NA::add_ref
行clang
很高兴编译测试。
把我的例子放到实际的角度来看,你可以认为那act
是一个方法boost::intrusive_ptr
,add_ref(A*)
曾经intrusive_ptr_add_ref(CBase*)
和B
曾经是一些模板,从 base 派生CBase
。
关于这个我有几个问题:
拒绝我
clang
的测试程序gcc
并且Comeau
不遵循标准是正确的吗?标准指定这种不切实际的行为(不允许模板类基作为关联的命名空间)是否有原因?
clang
基于以下原因接受我的测试程序与using NA::add_ref
指令是错误的3.4.2/3
吗?我应该报告错误吗?:)
PS 我已阅读clang Language Compatibility FAQ并没有在那里找到答案。