使用以下代码,clang 3.0 给出error: lookup of 'N' in member access expression is ambiguous
,而 clang 3.4 和 gcc 4.8 都接受代码而没有错误。
struct B
{
struct M
{
void f()
{
}
};
};
namespace N
{
struct M
{
void f()
{
}
};
}
template<typename>
struct A : N::M, B::M
{
typedef B N;
};
struct D : A<int>
{
A<int> m;
void f()
{
m.N::M::f(); // found class-name 'A<int>::N' (unambiguous)
}
};
template<typename T>
struct C : A<T>
{
A<T> m;
void f()
{
m.N::M::f(); // found namespace-name 'N' (ambiguous?)
}
};
template struct C<int>;
在查阅标准后,我不清楚关于C<T>::f()
.
因为N
在对象表达式的类范围n
(依赖)和整个后缀表达式的上下文(即函数的范围C<T>::f()
)中查找,所以需要延迟查找直到实例化点.
N
在实例化时,如果同时找到命名空间和 typedef ,查找将是不明确的A<T>::N
。的声明N
只有在没有被 的声明隐藏时才可见A<T>::N
。
问题是在“在整个后缀表达式的上下文中”和“在模板的定义点”查找时,名称空间是否N
应该被认为被 typedef 隐藏。A<T>::N
N
引自 C++ 工作草案标准 N3242=11-0012(2011 年 2 月):
3.4.5 类成员访问 [basic.lookup.classref]
如果类成员访问中的 id-expression 是以下形式的限定 id
class-name-or-namespace-name::...
.
or运算符后面的类名或命名空间名在整个后缀表达式的上下文和对象表达式的类的范围内->
都被查找。如果名称仅在对象表达式的类范围内找到,则该名称应指类名。如果该名称仅在整个后缀表达式的上下文中找到,则该名称应指类名或命名空间名。如果在两个上下文中都找到该名称,则类名或命名空间名应指同一实体。14.6.4 从属名称解析 [temp.dep.res]
在解析从属名称时,会考虑来自以下来源的名称:
—在模板定义时可见的声明。
— 来自实例化上下文 (14.6.4.1) 和定义上下文中与函数参数类型相关联的命名空间的声明。