我有一些代码,出于这个问题的目的,可以归结为
template<typename T>
class TemplateClass : public T {
public:
void method() {}
template<typename U>
static void static_method(U u) { u.TemplateClass::method(); }
};
class EmptyClass {};
int main() {
TemplateClass<TemplateClass<EmptyClass> > c;
TemplateClass<EmptyClass>::static_method(c);
}
我试图用两个编译器的多个版本来编译它。 GCC 4.2、4.4、4.6会毫无保留地接受它。截至11月14日,Clang 2.9和SVN干线拒绝它并显示以下错误消息:
example.cc:6:38: error: lookup of 'TemplateClass' in member access expression is
ambiguous
static void static_method(U u) { u.TemplateClass::method(); }
^
example.cc:13:3: note: in instantiation of function template specialization
'TemplateClass<EmptyClass>::static_method<TemplateClass<TemplateClass<EmptyClass>
> >' requested here
TemplateClass<EmptyClass>::static_method(c);
^
example.cc:2:7: note: lookup in the object type
'TemplateClass<TemplateClass<EmptyClass> >' refers here
class TemplateClass : public T {
^
example.cc:2:7: note: lookup from the current scope refers here
1 error generated.
哪一个错了?我可以通过更改来解决Clang
static void static_method(U u) { u.TemplateClass::method(); }
至
static void static_method(U u) { u.TemplateClass<T>::method(); }
但我想对何时可以删除模板参数的理解充满信心。
编辑:我曾认为歧义是在
TemplateClass
的两个实例之间。以下代码使用GCC和Clang进行编译,从而使该假设受到质疑:class E {};
template<typename T>
class A : public T {
public:
void method() {}
};
int main() {
A<A<E> > a;
a.A::method();
}
最佳答案
我相信clang正确地拒绝了此代码。
lang发现的歧义可以用一个不太复杂的例子来再现:
template<typename T>
class TemplateClass {
public:
void method() {}
template<typename U>
static void static_method(U u) { u.TemplateClass::method(); }
};
struct A {};
struct B {};
int main() {
TemplateClass<A> c;
TemplateClass<B>::static_method(c);
}
这里,模板中的继承被省略,并且两个独立的类用于实例化。铛产生的错误保持不变。
首先,由于类名注入(inject),在
TemplateClass<T>
的范围内,名称TemplateClass
指的是TemplateClass<T>
。这就是静态方法可以使用TemplateClass::method
而不是更明确的TemplateClass<T>::method
的原因。在C++ 11和C++ 98标准的“3.4.5类成员访问[base.lookup.classref]”中定义了用于解释静态方法中的
u.TemplateClass::method
的名称查找。相关部分是3.4.5/4:
就是这种情况。 id-expression是
.
右边的部分,在我们的例子中,这是限定名称TemplateClass::method
。“整个postfix-expression的范围”是静态函数的主体,在此静态函数中,
TemplateClass
表示TemplateClass<B>
,因为该函数是该类的成员(我们称为TemplateClass<B>::static_method
)。因此,在此范围内,名称是
TemplateClass<B>
。“对象表达式”是
.
的左侧部分,在本例中为c
。 c
的类别为TemplateClass<A>
,在该类别的范围内,TemplateClass
表示TemplateClass<A>
。因此,根据查找所使用的范围,名称是指不同的实体。
该标准现在说:
在我们的程序中不是这种情况。程序格式错误,要求编译器给出诊断消息。
如果将
B
替换为问题中使用的TemplateClass<A>
,则歧义保持不变。关于c++ - 含糊的成员访问表达式: is Clang rejecting valid code?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8100492/