类模板出现在类成员访问表达式中

时间:2014-06-23 04:56:57

标签: c++ class templates language-lawyer

引自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

在对象表达式类范围内找不到标识符后,查找是什么意思?

3 个答案:

答案 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
}