为什么即使模板 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 模板被实例化(所以你需要 typename
在 SomeOtherTemplate<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.
这是依赖名称的名称查找规则。
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 等细节。结果可能不会像您显示的示例代码那样发生变化,但它只是将名称查找推迟到已知类型,以做出最准确的决定。
以下代码可以编译无误:
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
您的代码是 "ill-formed, no diagnostic required",因为 A::f
从来没有有效的专业化。事实上,规范说 this->whatever
既不是未知特化的成员(因为没有依赖基 class),也不是当前实例化的成员(因为它没有在非依赖基础 class,也不在 class 模板本身中)。这还会使您的代码无效,并且再次不需要诊断(但允许)。这在
this
依赖于类型,因为您还不知道定义中的模板参数值。所以比如 SomeOtherTemplate<decltype(*this)>
不能立即解析,而是需要等到 this
的 class 模板被实例化(所以你需要 typename
在 SomeOtherTemplate<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.
这是依赖名称的名称查找规则。
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 等细节。结果可能不会像您显示的示例代码那样发生变化,但它只是将名称查找推迟到已知类型,以做出最准确的决定。