可以编译以下代码而不会出现错误:
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
的名称查找 .
我可以理解 this
是类型相关的,如果类模板具有类型相关的基础,如:
template <typename T> struct B { T whatever; };
template <typename T> struct A : B<T> {
void f() { this->whatever; }
};
int main() {
A<int> a;
}
在解析模板类 A
的定义时,它的基础类型为's impossible to know what',这使得 this->whatever
可能合法( B<T>
可能有一个名为 whatever
的成员) . 相反,一旦在某处使用成员函数 f
,我就没有看到任何潜在的 this->whatever
在第一个例子中是合法的 .
那么,在第一个例子的某些方面,_2971621是否合法?如果没有,在这种情况下是否还有其他原因应将 this
视为类型依赖表达式?
3 回答
您的代码是"ill-formed, no diagnostic required",因为
A::f
永远不会有有效的专业化 . 事实上,规范说this->whatever
既不是未知专门化的成员(因为没有依赖的基类),也不是当前实例化的成员(因为它没有在非依赖基类中声明,也没有在类中声明模板本身) . 此外,这会使您的代码无效,并且不再需要诊断(但允许) . 有关详情,请参阅https://stackoverflow.com/a/17579889/34509this
是类型相关的,因为您还不知道定义中的模板参数值 . 因此,例如SomeOtherTemplate<decltype(*this)>
无法立即解决,但需要等到this
的类模板被实例化(因此在SomeOtherTemplate<decltype(*this)>::type
之前需要typename
) .但是,仅仅因为
this
是类型依赖的,并不意味着this->whatever
也是如此 . 如上所述,规范具有将其正确归类为无效的工具,实际上也不会使this->whatever
类型依赖 . 它说您的示例可以进一步简化:
语句
this = 1;
永远不应该编译,即使A<T>
具有类型相关的基类,也无法修复 . 但是,在实例化函数A<T>::f()
之前,编译器不会抱怨 .由于Johannes Schaub - litb已经answered这可能是"no diagnostic required"情况 .
这是关于从属名称的名称查找规则 .
$14.6/9 Name resolution [temp.res]:
意图是,如果名称取决于模板参数,则信息不足,直到知道实际模板参数 . 编译器赢了't distinguish the dependent names'类型(由
this
或其他形成),不会检查类有没有依赖基类的详细信息 . 结果可能不会像您展示的示例代码那样改变,但它只是推迟名称查找,直到类型已知,才能做出最准确的决策 .