考虑以下程序:
struct S {
using T = float;
operator T() { return 9.9f; }
};
int main() {
S m;
S::T t = m;
t = m.operator T(); // Is this correct ?
}
该程序在g++中编译得很好(参见现场演示在这里)
但是在clang++, msvc++ &Intel c++编译器
clang++给出了以下错误(参见现场演示这里)
main.cpp:8:20: error: unknown type name 'T'; did you mean 'S::T'?
t = m.operator T(); // Is this correct ?
^
S::T
main.cpp:2:11: note: 'S::T' declared here
using T = float;
msvc++给出了以下错误(参见现场演示这里)
source_file.cpp(8): error C2833: 'operator T' is not a recognized operator or type
source_file.cpp(8): error C2059: syntax error: 'newline'
英特尔c++编译器也拒绝此代码(参见现场演示在这里)
那么,问题是哪个编译器在这里?这里是g++不正确还是其他3个编译器不正确?
[basic.lookup.classref]/7:
如果id-expression是转换函数id,则首先在对象表达式的类中查找其转换类型id,如果找到,则使用名称。否则,它将在整个上下文中查找 后缀表达式。在这些查找中,只考虑表示类型的名称或专门化为类型的模板。(例子:
struct A { }; namespace N { struct A { void g() { } template <class T> operator T(); }; } int main() { N::A a; a.operator A(); // calls N::A::operator N::A }
- 结束示例]
这表明该示例可以正常运行,尽管在上面的示例中,A
先前已被声明为类型名,对main
可见。
这在核心问题156中讨论过,早在1999年就提交了:
如何:
struct A { typedef int T; operator T(); }; struct B : A { operator T(); } b; void foo() { b.A::operator T(); // 2) error T is not found in the context // of the postfix-expression? }
这个解释正确吗?还是说他的意图是只有在两个作用域中都发现
T
并且引用不同时才会出现错误实体?Erwin Unruh:目的是你在两种情况下都要看。如果你只找到一次,那就是标志。如果在两个符号中都找到它,则两个符号在某些方面必须是"相同的"。(如果你没有找到,这是一个错误)。
所以我想说Clang错了:从某种程度上说,Clang的意图是我们发现了T
,即使只是在类中。