C++ 我相信这是一个叮当作响的bug++;与访问类';政府的公共成员职能
叮当作响的声音如下:C++ 我相信这是一个叮当作响的bug++;与访问类';政府的公共成员职能,c++,language-lawyer,public,clang++,C++,Language Lawyer,Public,Clang++,叮当作响的声音如下: #include <iostream> void f() { std::cout << "f()\n"; } struct S { typedef void(*p)(); operator p() { return f; } }; int main() { S s; s.operator p()(); } 但是它应该,因为表达式s.operator p()()访问对象s::s的公共成员函数。我错过什么了吗 如果
#include <iostream>
void f() { std::cout << "f()\n"; }
struct S {
typedef void(*p)();
operator p() { return f; }
};
int main()
{
S s;
s.operator p()();
}
但是它应该,因为表达式s.operator p()()
访问对象s::s
的公共成员函数。我错过什么了吗
如果我错了,我希望能引用标准中的一句话来支持答案。这似乎是一个叮当声中的错误。我相信代码是正确的 Clang 4.0.0报告:
<source>:13:16: error: unknown type name 'p'; did you mean 'S::p'?
s.operator p()();
^
:13:16:错误:未知类型名称“p”;你是说“S::p”吗?
s、 算子p()();
^
但是,从C++143.4.5/7[basic.lookup.classref]
如果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
}
struct A{};
名称空间N{
结构A{
void g(){}
模板算子T();
};
}
int main(){
N::A;
a、 算子a();
//调用N::A::运算符N::A
}
-[结束示例]
在您的示例中,类型
p
应该在类中找到,而不需要限定。您的链接说明了一切:“您的意思是'S::p'?”请将编译器错误粘贴到问题中,而不仅仅是链接到它们。转换运算符的名称查找使用类型匹配,而不是词汇(字符)匹配。即使您说了s.operator decltype(&f)(
),查找也会成功。不过,这段代码看起来格式不错,因为规范中说“如果id表达式是转换函数id,则首先在对象表达式的类中查找其转换类型id,并使用名称(如果找到)。”。所以这闻起来真像是叮当作响中的一个bug……这里的问题是是否应该首先在类范围内查找p
。gcc和clang有所不同。经过进一步分析,我认为我没有真正理解句子的原因,否则它会在[basic.lookup.classref]/7中的整个后缀表达式的上下文中查找。请注意,所示示例无法编译。你能举个例子说明上面的句子有什么用处吗?在这个例子中,类型名A
在N::A
的上下文中被正确查找,给出了注入的类名,意思是N::A
。在访问的对象中没有任何这样的运算符这一事实是一个单独的错误。下面是一个示例,其中在类类型的作用域中查找名称失败,但在整个后缀表达式的作用域中查找名称成功:在调用b.operator a()中
,在N::B
的范围内没有名称A
,但是在调用函数M::f
的范围内可以找到M::A
。@aschepler感谢您的评论。我最终得出结论,链接中的示例显示了在整个后缀表达式的范围内使用名称查找。
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
}