【问题标题】:Class template appeared in the class member access expression类模板出现在类成员访问表达式中
【发布时间】:2014-06-23 04:56:57
【问题描述】:

引自 3.4.5/1(文档版本 N3797):

在类成员访问表达式 (5.2.5) 中,如果 .或 -> 令牌是 紧跟一个标识符,后跟一个 应命名一个类模板。

#include <iostream>
#include <stdio.h>

struct A { };

template <typename T> class B{ };


int main(){ A *a = new A(); a->B<int>; }

在整个后缀表达式的上下文中查找B&lt;int&gt; 是成功的。但是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

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

【问题讨论】:

  • 解释什么?除了它所说的之外,该诊断是否还有其他可能的解释?
  • @Praetorian 我已经更新了我的问题。
  • 我更喜欢新的。
  • 确实好多了,我不知道整个后缀表达式的上下文是什么意思。
  • 我不确定它是否适用于从属名称。我什至怀疑这是规则的初衷。但它似乎适用于这种情况。正如我所说,也许对 CWG1111 的讨论可以对标准中的这一段有所了解。

标签: c++ class templates language-lawyer


【解决方案1】:

您的构造被 §5.2.5[expr.ref]/p2 禁止,解决类成员访问表达式:

在任何一种情况下,id-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(); 
}

A 中查找base 不会找到它,因此您还需要在表达式的上下文中查找,以确定&lt; 是否小于或启动模板参数列表。然而,这个子句有相当长的历史(早于模板别名),所以我必须有另一个用例......

【讨论】:

  • 这里没有解释如果没有找到标识符,则在整个后缀表达式的上下文中查找它并命名一个类模板。从 3.4.5/1 开始。
  • @RSahu 你能解释一下这是什么意思吗?
  • @DmitryFucintv,我绞尽脑汁想明白这句话,但我无法弄清楚。
  • @RSahu 在我发布此内容时,该问题尚未编辑。
  • 迟到总比不到好:this 会是您正在寻找的缺失用例吗?
【解决方案2】:

一个简单的例子,如果没有找到标识符,然后在整个后缀表达式的上下文中查找它并命名一个类模板的含义就很清楚了。

#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;
}

【讨论】:

  • 那么到底什么情况下会在整个后缀表达式的上下文中查找标识符?
  • 嗯,Bs 是从表达式的上下文中查找的吗?我认为它们被发现为注入类名称。如果将基类放在单独的命名空间中,它仍然可以是found
  • @T.C.看来你是对的。这是因为第 10.2 条。
【解决方案3】:

我认为这条规则的意义是查找表示类成员的名称的别名。下面是一个简单的例子:

#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
}

【讨论】:

  • 这个标识符B后面没有&lt;
  • 其实这里指的是规则3.4.5/3。但我认为这与 R Sahu 在他的回答中指定的含义相同。
猜你喜欢
  • 2020-08-23
  • 1970-01-01
  • 2012-09-12
  • 2010-12-08
  • 1970-01-01
  • 1970-01-01
  • 2017-11-27
  • 2017-09-08
  • 2018-09-18
相关资源
最近更新 更多