【发布时间】:2013-08-15 14:57:10
【问题描述】:
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 是以下形式的限定 id 类名或命名空间名::... . 后面的类名或命名空间名。 or -> 运算符是首先在类中查找的 对象表达式和名称(如果找到)将被使用。否则在整个上下文中查找 后缀表达式。 [ 注意:见 3.4.3,它描述了在 :: 之前查找名称,只会找到一个 类型或命名空间名称。 ——尾注]
如果id-expression是一个conversion-function-id,它的conversion-type-id是首先在 对象表达式和名称(如果找到)将被使用。否则在整个上下文中查找 后缀表达式。在这些查找中的每一个中,只有表示其特化的类型或模板的名称 是类型被考虑。
14.6.2 从属名称 [temp.dep]
在模板中,一些结构的语义可能因实例而异。这样一个 构造取决于模板参数。特别是,类型和表达式可能取决于类型 和/或模板参数的值(由模板参数确定),这决定了 某些名称的名称查找上下文。表达式可能依赖于类型(取决于模板的类型 参数)或值依赖(取决于非类型模板参数的值)。
[...]
这些名称是未绑定的,并且在模板实例化的点上查找 (14.6.4.1) 模板定义的上下文和实例化点的上下文。
14.6.2.1 依赖类型 [temp.dep.type]
一个名字是一个未知专业的成员,如果它是
[...]
— 表示类成员访问表达式中的成员的 id 表达式 (5.2.5),其中任一
——对象表达式的类型是当前实例化,当前实例化至少有 一个依赖基类,并且 id-expression 的名称查找未找到 当前实例化或其非依赖基类;或
——对象表达式的类型是依赖的,不是当前的实例化。
[...]
一个类型是依赖的,如果它是
— 未知专业的成员,
【问题讨论】:
-
在第一行中,
Dependent是一个类型或命名空间名称。在第二行中,Dependent是一个类型名称。 -
我有理由确定
Dependent是一个非依赖名称。 -
@willj:在第一行中,您认为
t.Namespace::f或t.Type::f是什么意思? -
@dribeas:添加了模板的实例化,以澄清(并证明至少有一个有效的实例化)
-
我不确定这是否相关,但之前的规则 (C++03) 不允许
t.operator Dependent*();。变化见DR1111的分辨率
标签: c++ templates language-lawyer