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

时间:2016-08-30 04:37:07

标签: c++ templates dependent-name

The following code can be compiled without error:

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

And I know it's because this is a type-dependent expression, which makes name lookup for whatever is postponed until the actual template argument is known. Since member function f() is never used in this case, so that no instantiation of A<T>::f exists, and name lookup for whatever is never performed.

I can understand that this is type-dependent if the class template has a type-dependent base like:

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

When parsing the definition of template class A, it's impossible to know what's type of its base, which makes this->whatever potentially legal (B<T> could has a member named whatever). On the contrary, I haven't see any potential that this->whatever would be legal in the first example as soon as member function f is used somewhere.

So, could this->whatever be legal at some points in the first example? If not, is there any other reason that this should be treated as type-dependent expression in that case?

3 个答案:

答案 0 :(得分:4)

您的代码“格式错误,无需诊断”,因为A::f永远不会有有效的专业化。事实上,规范说this->whatever既不是未知专门化的成员(因为没有依赖基类),也不是当前实例化的成员(因为它没有在非依赖基类中声明,也不在课堂模板本身)。此外,这会使您的代码无效,并且不再需要诊断(但允许)。这在https://stackoverflow.com/a/17579889/34509

中有更详细的解释

this与类型有关,因为您还不知道定义中的模板参数值。因此,例如SomeOtherTemplate<decltype(*this)>无法立即解决,但需要等到this的类模板被实例化(因此在typename之前需要SomeOtherTemplate<decltype(*this)>::type)。

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

  

如果表达式引用当前实例化的成员并且引用的成员的类型是依赖的,或者类成员访问表达式引用成员,则类成员访问表达式([expr.ref])依赖于类型一个未知的专业化。

答案 1 :(得分:0)

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

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

语句this = 1;永远不应该编译,即使A<T>具有类型相关的基类,也无法修复。但是,在实例化函数A<T>::f()之前,编译器不会抱怨。

由于Johannes Schaub - litb已经answered,这可能是“无需诊断”的情况。

答案 2 :(得分:0)

这是关于从属名称的名称查找规则。

$14.6/9 Name resolution [temp.res]

  

在查找模板定义中使用的名称声明时,通常的查找规则([basic.lookup.unqual],[basic.lookup.argdep])用于非依赖名称。依赖于模板参数的名称查找被推迟,直到知道实际模板参数([temp.dep])。

意图是,如果名称取决于模板参数,则信息不足,直到知道实际模板参数。编译器不会区分依赖名称&#39;类型(由this或其他人形成),不会检查详细信息,例如类是否具有依赖基类。结果可能不会像您展示的示例代码那样改变,但它只是推迟名称查找,直到知道类型,才能做出最准确的决定。