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

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

问题描述

我决定在有效的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> ,但 T 是一个模板参数,
直到后来(当 B 被实例化时)。不知道 T
是什么,没有办法知道类 A 。特别是,没有办法知道它是否有 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.

上述代码是否正确? / strong>

Is the above code correct or not?

推荐答案

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 的基础。原因是编译器不可能知道实例化的类型是否存在可能不包含任何成员的 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< T> 是一种具体类型。另一个选择是用定义它的类限定:

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 >

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天全站免登陆