以下代码被 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
都将“在对象表达式的类中查找” t
。作为t
一个依赖于类型的表达式,查找应该推迟到模板被实例化。
有什么我想念的吗?
编辑:如果打算这样的名称不依赖,那么这个决定的理由是什么?我可以看到,如果实现者不必推迟对诸如命名空间或类型名称之类的构造的评估,那么它会使实现者的生活更t.operator X::Dependent*
轻松。我不清楚这是当前措辞的有意还是无意的副作用。t.X::Dependent::f
X
C++ 工作草案 N3337 的相关引用:
3.4.5 类成员访问 [basic.lookup.classref]
如果类成员访问中的 id-expression 是 class-name-or-namespace-name::... 形式的限定 id,则 . 或 -> 运算符首先在对象表达式的类中查找,如果找到,则使用名称。否则在整个后缀表达式的上下文中查找它。[注意:见 3.4.3,它描述了在 :: 之前查找名称,它只会找到类型或命名空间名称。——尾注]
如果 id-expression 是转换函数 ID,则首先在对象表达式的类中查找其转换类型 ID ,如果找到,则使用名称。否则在整个后缀表达式的上下文中查找它。在这些查找中的每一个中,只考虑表示类型或特化为类型的模板的名称。
14.6.2 从属名称 [temp.dep]
在模板内部,一些结构的语义可能因一个实例化而异于另一个实例化。这样的构造取决于模板参数。特别是,类型和表达式可能取决于模板参数的类型和/或值(由模板参数确定),这决定了某些名称的名称查找上下文。表达式可以是类型相关的(取决于模板参数的类型)或值相关的(取决于非类型模板参数的值)。
[...]
此类名称是未绑定的,并且在模板定义的上下文和实例化点的上下文中都在模板实例化点 (14.6.4.1) 处查找。
14.6.2.1 依赖类型 [temp.dep.type]
一个名字是一个未知专业化的成员,如果它是
[...]
—一个 id 表达式,表示类成员访问表达式(5.2.5) 中的成员,其中任一
——对象表达式的类型为当前实例化,当前实例化至少有一个依赖基类,id-expression的名称查找没有找到当前实例化的成员或其非依赖基类;或者
—对象表达式的类型是依赖的,不是当前的实例化。
[...]
一个类型是依赖的,如果它是
—未知专业的成员,