我有一些代码,出于这个问题的目的,可以归结为

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>

“对象表达式”是.的左侧部分,在本例中为cc的类别为TemplateClass<A>,在该类别的范围内,TemplateClass表示TemplateClass<A>

因此,根据查找所使用的范围,名称是指不同的实体。

该标准现在说:



在我们的程序中不是这种情况。程序格式错误,要求编译器给出诊断消息。

如果将B替换为问题中使用的TemplateClass<A>,则歧义保持不变。

关于c++ - 含糊的成员访问表达式: is Clang rejecting valid code?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8100492/

10-11 17:06