我有一个模板类NB::B<T>
,它来自命名空间中的非模板类NA::A
。 act<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
的行为似乎是正确的。 Comeau
和gcc
正在接受错误的计划。
同时,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
。
关于这一点,我有几个问题:
我是对的,clang
是否正确拒绝我的测试计划,gcc
和Comeau
不符合标准?
标准是否指定了这种不切实际的行为(禁止将模板类库作为关联的命名空间)?
clang
错误接受using NA::add_ref
指令的3.4.2/3
错误接受我的测试程序?
我应该报告错误吗? :)
P.S。我看过clang Language Compatibility FAQ并没有在那里找到答案。
答案 0 :(得分:6)
从n3337开始,基本上是C ++ 11,只有很少的编辑修改,3.4.2 / 2读取:
对于函数调用中的每个参数类型T [...]的集合 名称空间和类的确定方式如下:[...]
- 如果T是类类型(包括联合),则其关联的类是:类本身;它所属的成员,如果有的话;和其直接和间接基类。其关联的名称空间是其关联类是成员的名称空间。 此外,如果T是类模板专业化,...
然后继续使用您在问题中发布的相同报价。这里的重要区别是此外,这意味着您引用的列表(我省略了)是对已经提到的名称空间的补充,其中包括基类所属的名称空间
Gcc和comeau是对的,clang ++拒绝代码是错误的。
&LT;不适用&gt;
Clang ++在没有using NA::add_ref
的情况下拒绝它是错误的。
是的,你应该报告一个错误。它似乎已经被报告并修复了。