为什么我可以从派生类调用基模板类方法 [英] Why can I call base template class method from derived class

查看:28
本文介绍了为什么我可以从派生类调用基模板类方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我决定测试Effective C++"中的一个示例,但没有得到预期的结果.所以,显然这个(简化的)代码不应该编译:

I decided to test one of the examples in "Effective C++" and I'm not getting the result I expected. So, apparently this (simplified) code shouldn't compile:

template <class T>
struct A {
    void f(){}
};

template <class T>
struct B : public A <T> {
    void f2() { f(); }   // calling base function - will not compile
};

以下是解释(为了简单起见,类名已更改):

Here's the explanation (class names changed for simplicity) :

上面的代码不能编译,至少在符合标准的编译器中不能.这样的编译器会抱怨 f 不存在.我们可以看到 f 在基类中,但编译器不会在那里寻找它.

The code above won't compile, at least not with conformant compilers. Such compilers will complain that f doesn't exist. We can see that f is in the base class, but compilers won't look for it there.

我们需要了解原因.问题是当编译器遇到类模板 B 的定义时,它们不知道它继承自哪个类.当然,它是 A,但 T 是一个模板参数,一个直到以后才会知道(当 B 被实例化时).不知道什么T也就是说,没有办法知道 A<T> 类是什么样的.特别是,没有办法知道它是否有 f 函数.

We need to understand why. The problem is that when compilers encounter the definition for the class template B, they don't know what class it inherits from. Sure, it's A<T>, but T is a template parameter, one that won't be known until later (when B is instantiated). Without knowing what T is, there's no way to know what the class A<T> looks like. In particular, there's no way to know if it has a f function.

我的编译器 (Visual Studio) 不介意...它甚至不显示任何警告.

My compiler (Visual Studio) doesn't mind... It doesn't even show any warnings.

以上代码是否正确?

推荐答案

template <class T>
struct A {
    void f(){}
};

template <class T>
struct B : public A <T> {
    void f2() { f(); }   // calling base function - will not compile
};

在派生模板中,表达式 f() 不依赖于任何模板参数,因此编译器会在第一阶段查找期间尝试解析它.此时,模板还没有用类型实例化,编译器不会查看基本的 A<T>.原因是编译器不可能知道对于实例化的类型是否存在可能不包含任何成员的 A 特化.

In the derived template, the expression f() is not dependent on any template argument, so the compiler attempts to resolve it during the first phase lookup. At this point, the template has not yet been instantiated with the type, and the compiler won't look into the base A<T>. The reason is that the compiler could not possibly know whether for the type of the instantiation there is a specialization of A<T> that might not contain any members.

解决方案是使表达式依赖,最简单的方法是使用 this-> 进行限定:

The solution is to make the expression dependent, the simplest way would be to qualify with this->:

template <typename T>
void B<T>::f2() {  this->f(); }

由于表达式现在是相关的,查找被延迟到第二阶段,在该阶段替换类型并且 A 是一个具体类型.另一种选择是使用定义它的类进行限定:

As the expression is now dependent, lookup is delayed until the second phase, where the type is substituted and A<T> is a concrete type. Another alternative is qualifying with the class where it is defined:

template <typename T>
void B<T>::f2() { A<T>::f(); }

再次表达变得依赖,并将在第二阶段解决.主要区别在于,在第二种情况下,调用是合格的,因此它不使用动态调度.如果 A<T>::f() 是虚拟的,它仍然会执行 A<T>::f(),而不是最终的覆盖.

Again the expression becomes dependent and will be resolved during the second phase. The main difference is that in this second case, the call is qualified and thus it does not use dynamic dispatch. If A<T>::f() was virtual it would still execute A<T>::f(), and not the final overrider.

代码正确吗?不.VS 接受吗?是的.

Is the code correct? No. Does VS accept it? Yes.

这是 Visual Studio 编译器中已知的不符合项,未实现两阶段查找.它将模板内的所有查找延迟到第二阶段,此时查找成功.

This is a known non-conformance in the Visual Studio compiler, that does not implement two phase lookup. It delays all lookup inside the template to the second phase and at that point lookup succeeds.

这篇关于为什么我可以从派生类调用基模板类方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆