此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::vector
和foo::vector
。要解决此问题,您必须编写
f.foo::vector<int>();
我已经在所有流行的C ++编译器(g++
,clang++
,vc++
和Intel C ++)上尝试了该程序,并且所有编译器都对该程序进行了编译而没有任何错误。那么,为什么他说这个程序存在歧义呢? C ++标准对此有何看法?
答案 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期 修复了析构函数名称的类似问题,但缺少成员 功能。