【发布时间】:2013-08-14 22:35:15
【问题描述】:
使用以下代码,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是否应该被认为在查找N“在整个后缀表达式的上下文中”和“在定义点时被typedef A<T>::N隐藏模板”。
引自 C++ 工作草案标准 N3242=11-0012(2011 年 2 月):
3.4.5 类成员访问 [basic.lookup.classref]
如果类成员访问中的 id-expression 是形式的限定 id
class-name-or-namespace-name::...
.或->运算符后面的类名或命名空间名在 的上下文中查找 整个后缀表达式,并且在对象表达式的类的范围内。如果名称仅在 对象表达式的类的范围,名称应指类名。如果找到名字 仅在整个后缀表达式的上下文中,名称应引用类名或命名空间名。 如果在两个上下文中都找到该名称,则类名或命名空间名应指同一个 实体。14.6.4 从属名称解析 [temp.dep.res]
在解析从属名称时,会考虑来自以下来源的名称:
— 在模板定义处可见的声明。
——来自与函数参数类型相关的命名空间的声明 实例化上下文 (14.6.4.1) 和定义上下文。
【问题讨论】:
-
怎么会想出这样的代码?
-
@jrok:空闲时间太多
-
在编写 C++ 解析器时总是出现这种东西;)
-
顺便说一句,引用的标准是什么?
-
@jrok 它是 C++98 或 C++03。这在 C++11 中有所改变。 (这说明旧版本做了不同的事情。)
标签: c++ templates language-lawyer