为什么即使模板 class 没有基数 class,`this` 也是一个依赖于类型的表达式?

Why `this` is a type-dependent expression even if the template class has no base class?

以下代码可以编译无误:

template <typename T> struct A {
    void f() { this->whatever; } // whatever is not declared before
};
int main() {
    A<int> a;
}

我知道这是因为 this 是一个依赖于类型的表达式,这使得 whatever 的名称查找被推迟到知道实际的模板参数为止。由于在这种情况下从未使用成员函数 f(),因此 A<T>::f 的实例化不存在,并且从未执行 whatever 的名称查找。

如果 class 模板有一个类型依赖的基础,我可以理解 this 是类型依赖的:

template <typename T> struct B { T whatever; };
template <typename T> struct A : B<T> {
    void f() { this->whatever; }
};
int main() {
    A<int> a;
}

在解析模板 class A 的定义时,不可能知道它的基类是什么类型,这使得 this->whatever 可能合法(B<T> 可能有一个名为 whatever 的成员)。相反,我没有看到 this->whatever 在第一个示例中只要在某处使用成员函数 f 就合法的任何可能性。

那么,在第一个示例中,this->whatever 在某些方面是否合法?如果不是,在这种情况下是否还有其他原因将 this 视为依赖于类型的表达式?

您的示例可以进一步简化:

template <typename T> struct A {
    void f() { this = 1; }
};
int main() {
    A<int> a;
}

语句 this = 1; 永远不会编译,即使 A<T> 有类型依赖的基础 class 也无法修复。然而,编译器不会抱怨,直到函数 A<T>::f() 被实例化。

因为 Johannes Schaub - litb has already 这可能是 "no diagnostic required" 的情况。

您的代码是 "ill-formed, no diagnostic required",因为 A::f 从来没有有效的专业化。事实上,规范说 this->whatever 既不是未知特化的成员(因为没有依赖基 class),也不是当前实例化的成员(因为它没有在非依赖基础 class,也不在 class 模板本身中)。这还会使您的代码无效,并且再次不需要诊断(但允许)。这在

中有更详细的解释

this 依赖于类型,因为您还不知道定义中的模板参数值。所以比如 SomeOtherTemplate<decltype(*this)> 不能立即解析,而是需要等到 this 的 class 模板被实例化(所以你需要 typenameSomeOtherTemplate<decltype(*this)>::type 之前) .

然而,仅仅因为 this 是类型相关的,并不意味着 this->whatever 也是。如上所述,该规范具有将其正确归类为无效的工具,实际上 not 也使 this->whatever 类型依赖。它说

A class member access expression ([expr.ref]) is type-dependent if the expression refers to a member of the current instantiation and the type of the referenced member is dependent, or the class member access expression refers to a member of an unknown specialization.

这是依赖名称的名称查找规则。

$14.6/9 名称解析 [temp.res]:

When looking for the declaration of a name used in a template definition, the usual lookup rules ([basic.lookup.unqual], [basic.lookup.argdep]) are used for non-dependent names. The lookup of names dependent on the template parameters is postponed until the actual template argument is known ([temp.dep]).

目的是,如果名称取决于模板参数,则信息是不够的,直到知道实际的模板参数。编译器不会区分依赖名称的类型(由 this 或其他人组成),不会检查 class 是否具有依赖基础 class 等细节。结果可能不会像您显示的示例代码那样发生变化,但它只是将名称查找推迟到已知类型,以做出最准确的决定。