clang和gcc都拒绝以下代码
template<typename T>
void f(T t)
{
t.Dependent::f(); // clang accepts, gcc rejects
t.operator Dependent*(); // both reject
}
struct Dependent
{
void f();
};
struct A : Dependent
{
operator Dependent*();
};
template void f<A>(A);
我对该标准的解读表明这两种表达都应该被接受 .
在这两种情况下, Dependent
只能是类型名称 .
在这两种情况下,名称 Dependent
都是"looked up in the class of the object expression" t
. 由于 t
是类型相关的表达式,因此应该延迟查找,直到模板被实例化为止 .
有什么我想念的吗?
EDIT :如果打算这样的名称不依赖,那么这个决定的理由是什么?我可以看到,如果它们不必延迟对 t.operator X::Dependent*
或 t.X::Dependent::f
这样的构造的评估,它可以使实现者的生活更轻松,其中 X
可以是命名空间或类型名称 . 我不清楚这是否是当前措辞的预期或非预期的副作用 .
C工作草案N3337的相关引用:
3.4.5类成员访问[basic.lookup.classref]如果类成员访问中的id-expression是class-name-or-namespace-name :: ...形式的qualified-id,则为class-name -or-namespace-name跟随 . 或 - >运算符首先在对象表达式的类中查找,如果找到,则使用名称 . 否则,它将在整个postfix-expression的上下文中查找 . [注意:参见3.4.3,它描述了在::之前查找名称,它只能找到一个类型或命名空间名称 . -end note]如果id-expression是convert-function-id,则首先在对象表达式的类中查找其conversion-type-id,并使用名称(如果找到) . 否则,它将在整个postfix-expression的上下文中查找 . 在每个查找中,仅考虑表示其特化类型的类型或模板的名称 . 14.6.2从属名称[temp.dep]在模板内部,一些构造的语义可能因实例而异 . 这种结构取决于模板参数 . 特别是,类型和表达式可能取决于模板参数的类型和/或值(由模板参数确定),这决定了某些名称的名称查找的上下文 . 表达式可以是类型相关的(在模板参数的类型上)或依赖于值的(在非类型模板参数的值上) . [...]这些名称是未绑定的,并且在模板定义的上下文和实例化的上下文中都会查看模板实例化(14.6.4.1) . 14.6.2.1依赖类型[temp.dep.type]如果是[...],则名称是未知专门化的成员 - 表示类成员访问表达式(5.2.5)中成员的id-expression - 对象表达式的类型是当前实例化,当前实例化具有至少一个从属基类,并且id-expression的名称查找未找到当前实例化的成员或其非依赖基类;或 - 对象表达式的类型是依赖的,而不是当前的实例化 . [...]类型依赖于 - 如果是 - 未知专业化的成员,
1 回答
1
以下是我认为你的第一个案例
t.Dependent::f
的工作原理 . 首先,我相信(意思是,我不完全确定)14.6.2.1p5应该说"unqualified-id"而不是"id-expression" . 但与此无关,你的名字Dependent::f
实际上是由两个名字组成的(在标准中,每个嵌套的嵌套名称说明符后面跟着一个成员名称叫做"qualified-id",即使是语法上的,这些也不是qualified-id制作 . 所以a namefoo::bar::baz
是一个限定id,但也包含另外一个"qualified-id" aswell) .Dependent
和Dependent::f
. 前者不是"An id-expression denoting the member in a class member access expression",因此您不能简单地应用适用于Dependent::f
的规则也适用于Dependent
.Dependent
因此是非依赖的,虽然需要在依赖类型中查找,但必须在定义时找到它 . 我个人认为我们应该有一个说"When looking up a qualified-id where the qualifier is type-dependent, name lookup yields an empty result."的条款,以优雅地处理这些"force name-lookup to be done immediately" . 所以无论如何,最后,我认为你的第一个案例是不正确的,因为没有找到Dependent
(第3.4条不能仅仅通过第14条的首部自行决定该名称实际上是依赖的) .2
对于你的其他情况,
operator Dependent
,事情变得更容易 . 你又有两个名字,Dependent
和operator Dependent
. 我再次找到了没有什么说Dependent
在这里是一个从属名称(我不确定这是否是错的 . 这超出了我的意义) .运算符函数名称的名称查找比较(例如,名称查找哈希表的相等函数)是"they are conversion-function-ids formed with the same type"(3.8) . 这意味着为了形成名称本身(尚未进行名称查找!),您不仅需要像标识符一样提供词法拼写,而且还必须提供类型标识,这需要由
Dependent
.在
t.operator Dependent*
中查找依赖的id表达式只是意味着语义类型比较被延迟 . 尝试这个,这应该工作正常您的后续行动
我不知道理由,但我认为你已经给了一个好点 . 这看起来非常符合在查找非限定名称时跳过依赖基类的规则 . 而且我认为适用于该案例的理由适用于此案例 . 这使得更容易在程序员的函数模板上进行推理,尤其是 .
代码看起来很好,但是如果
T
恰好有Dependent
成员,突然Dependent
会有不同的绑定(因为首先我们被告知要查看t
's class, and then into the surrounding scope). Under my current understanding of the templating rules, the above always refers to the surrounding scope' sDependent
,所以上面的代码是"safe",关于这个陷阱 .