引自3.4.5 / 1(文件版本N3797):
在类成员访问表达式(5.2.5)中,如果是。或 - >令牌是 紧接着是一个标识符,后跟一个&lt ;,标识符 必须抬头确定是否<是一个开始 模板参数列表(14.2)或小于运算符。标识符 首先在对象表达式的类中查找。如果 找不到标识符,然后在上下文中查找 整个后缀表达式和应命名一个类模板。
#include <iostream>
#include <stdio.h>
struct A { };
template <typename T> class B{ };
int main(){ A *a = new A(); a->B<int>; }
在整个postfix-expression的上下文中查找B<int>
是成功的。但是clang ++会返回错误:
test.cpp:14:32: error: no member named 'B' in 'A'
请解释该诊断信息。
以下内容对我来说并不清楚:如果找不到整数,则clang ++会返回错误。但标准说If the identifier is not found, it is then looked up in the context of the entire postfix-expression and shall name a class template
。
在对象表达式类范围内找不到标识符后,查找是什么意思?
答案 0 :(得分:1)
你的构造被§5.2.5[expr.ref] / p2禁止,解决了类成员访问表达式:
在任何一种情况下, id-expression 都应该命名该类或其某个基类的成员。
如果找不到标识符,则在整个postfix-expression的上下文中查找它,并命名一个类模板。
我相信这个查找规则是用于查找作为模板的基类。查找“在对象表达式的类中”将找到类成员,但不会自己找到基类。这似乎不正确,因为基类名也被注入到派生类中(参见示例在§11.1[class.access.spec] / p5)。
编辑:嗯,这是一个非常人为的例子,似乎依赖于这条规则:
#include<iostream>
using namespace std;
template <class T>
class A {
public:
void foo() { cout << "A::foo()" << endl; }
};
template <class E>
using base = A<E>;
int main() {
A<int>* bp = new A<int>();
bp->base<int>::foo();
}
在base
中查找A
将找不到它,因此您需要在表达式的上下文中查找以确定<
是否小于或启动模板参数列表。但是这个子句有很长的历史(模板别名之前)所以必须有另一个我缺少的用例...
答案 1 :(得分:0)
一个简单的例子,其中的含义如果找不到标识符,则在整个postfix-expression的上下文中查找它,并命名一个类模板变得清晰。
#include <iostream>
template <typename T> struct B
{
T data;
};
struct A : B<int>
{
float data;
};
int main()
{
A *a = new A();
a->data = 25.3;
a->B<int>::data = 10; // Accessing the data from the base class, B<int>
// The name B is looked up from the context of the
// expression. B<int> is a base class. So, the
// expression is a way to get to the members of
// B<int>
a->B<float>::data = 10.1; // Not OK since B<float> is not a base class of A
std::cout << a->data << std::endl;
std::cout << a->B<int>::data << std::endl;
}
答案 2 :(得分:0)
我认为这条规则的意思是查找名称的别名,表示类成员。以下简单示例:
#include<iostream>
struct A
{
int a;
A(){ a = 5; }
};
typedef A B;
int main()
{
A *a = new A();
std::cout << a->B::a; //Usual unqualified name lookup applied
}