首页 文章

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

提问于
浏览
11

可以编译以下代码而不会出现错误:

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 回答

  • 4

    您的代码是"ill-formed, no diagnostic required",因为 A::f 永远不会有有效的专业化 . 事实上,规范说 this->whatever 既不是未知专门化的成员(因为没有依赖的基类),也不是当前实例化的成员(因为它没有在非依赖基类中声明,也没有在类中声明模板本身) . 此外,这会使您的代码无效,并且不再需要诊断(但允许) . 有关详情,请参阅https://stackoverflow.com/a/17579889/34509

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

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

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

  • 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这可能是"no diagnostic required"情况 .

  • 0

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

    $14.6/9 Name resolution [temp.res]

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

    意图是,如果名称取决于模板参数,则信息不足,直到知道实际模板参数 . 编译器赢了't distinguish the dependent names'类型(由 this 或其他形成),不会检查类有没有依赖基类的详细信息 . 结果可能不会像您展示的示例代码那样改变,但它只是推迟名称查找,直到类型已知,才能做出最准确的决策 .

相关问题