模棱两可的成员模板查找

时间:2018-10-04 03:46:44

标签: c++ language-lawyer function-call name-lookup

question的答案在以下代码中表示:

#include <vector>
using std::vector;

struct foo {
  template<typename U>
  void vector();
};

int main() {
  foo f;
  f.vector<int>(); // ambiguous!
}

main的最后一行是不明确的,因为编译器不仅在vector中查找foo,而且从main中查找为不合格的名称。因此它同时找到std::vectorfoo::vector。要解决此问题,您必须编写

f.foo::vector<int>();

我已经在所有流行的C ++编译器(g++clang++vc++和Intel C ++)上尝试了该程序,并且所有编译器都对该程序进行了编译而没有任何错误。那么,为什么他说这个程序存在歧义呢? C ++标准对此有何看法?

1 个答案:

答案 0 :(得分:10)

在C ++ 03中就是这种情况,但在C ++ 11中已修复。我们甚至可以尝试这个live in godbolt with clang using -std=c++03 flag。我们确实收到警告:

<source>:11:5: warning: lookup of 'vector' in member access expression is ambiguous; using member of 'foo' [-Wambiguous-member-template]

  f.vector<int>(); // ambiguous!
    ^

描述-Wambiguous-member-template的警告时,使用较旧的clang文档using the same example from the defect report below

此问题已通过defect report 1111: Remove dual-scope lookup of member template names 进行了更改,从而解释了该问题:

  

根据6.4.5 [basic.lookup.classref]第1段,

     
    

在类成员访问表达式(8.2.5 [expr.ref])中,如果。或->标记后紧跟一个标识符,后跟一个<,     必须查询标识符以确定<是否为     模板参数列表的开头(17.2 [temp.names])或     小于运算符。首先在的类中查找标识符     对象表达式。如果找不到标识符,则为     在整个后缀表达式的上下文中查找并应     为课程模板命名。如果在对象的类中查找     表达式找到一个模板,名称也在上下文中查找     整个postfix-expression和

         
        
  • 如果找不到名称,则使用在对象表达式的类中找到的名称,否则

  •     
  • 如果在整个postfix-expression的上下文中找到该名称,但未命名类模板,则找到该名称     在对象表达式的类中使用,否则

  •     
  • 如果找到的名称是一个类模板,则它应指向与对象表达式的类中找到的实体相同的实体,     否则程序格式错误。

  •     
  
     

这使以下格式不正确:

#include <set>
using std::set;
struct X {
  template <typename T> void set(const T& value);
};
void foo() {
  X x;
  x.set<double>(3.2);
}
     

那是令人困惑和不必要的。编译器已经完成了   在X的范围内查找,显然正确的分辨率是   不是postfix-expression范围的标识符。第305期   修复了析构函数名称的类似问题,但缺少成员   功能。