模板类与私有继承 [英] Template classes vs Private inheritance

查看:87
本文介绍了模板类与私有继承的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么有些编译器会坚持要求合格的成员是模板基类的公共成员,而对于非模板类则不需要相同的成员?请查看以下代码清单:

Why would some compilers insist on qualifying members public members of template base class while the not requiring the same for non-template class? Please look at the following code listings:

模板类:

#include <iostream>

using namespace std;

template <class T>
class TestImpl {
public: // It wont make a difference even if we use a protected access specifier here
    size_t vval_;
    TestImpl(size_t val = 0) : vval_(val) { }
};

template <class T>
class Test : public TestImpl<T> {
public:
    Test(size_t val) : TestImpl<T>(val) {
        cout << "vval_ : " << vval_ << endl; // Error: vval_ was not declared in this scope
        //! cout << "vval_ : " << TestImpl<T>::vval_ << endl; // this works, obviously
    }
};

int main() {
    Test<int> test1(7);

    return 0;
}

非模板类:

#include <iostream>

using namespace std;

class TestImpl {
public: // It wont make a difference even if we use a protected access specifier here
    TestImpl(size_t val = 0) : vval_(val) {}
    size_t vval_;
};

class Test : public TestImpl {
public:
    Test(size_t val) : TestImpl(val) {
        cout << "vval_ : " << vval_ << endl;
    }
};

int main() {
    Test test1(7);

    return 0;
}

上面的代码清单之间的显着区别是,虽然第一个清单使用模板类,但是第二个清单没有.

The significant difference between the above code listings is that while the first listing uses template classes, the second one doesn't.

现在,两个列表都可以使用 Microsoft的Visual Studio编译器(cl)正常编译,但是第一个列表 WONT 可以同时使用 Digital Mars编译器编译>(dmc)和 Windows的极简GNU (MinGW-g ++)编译器.我将收到类似"vval_未在范围内声明"的错误-我显然明白该错误的含义.

Now, both listings will compile fine with Microsoft's Visual Studio Compiler (cl) but the first listing WONT compile with both the Digital Mars Compiler (dmc) and Minimalist GNU for Windows (MinGW - g++) compiler. I will get an error like "vval_ was not declared in the scope" - an error I obviously understand what it means.

如果我有资格使用 TestImpl< T> :: vval _ 访问 TestImpl 的公共变量 vval _ ,则该代码将起作用.在第二个清单中,当派生类访问基类的 vval _ 变量而不对其进行限定时,编译器不会抱怨.

If I qualify access to the TestImpl's public variable vval_ using TestImpl<T>::vval_ the code works. In the second listing, the compilers do not complain when the derived class accesses the base class' vval_ variable without qualifying it.

关于这两个编译器以及可能的其他编译器,我的问题是为什么我应该能够直接从继承自非模板类的 vval _ 变量中直接访问(无限定条件) vval _ 变量非模板类,而我不能从从模板类继承的模板类做同样的事情?

With regard to the two compilers and possibly others, my question would be why I should be able to directly access (without qualifying) vval_ variable directly from a non-template class inheriting from a non-template class, while I cant do the same from a template class inheriting from a template class?

推荐答案

您面临的问题是,对于编译器vval_而言,它不是一个从属名称,因此它将尝试在实际实例化其之前进行查找.类型的模板.此时,编译器 [*] 尚不知道基本类型,因此它不考虑模板化的基本. Visual Studio不会执行两阶段查找,因此这里不需要这样做.

The problem you are facing is that for the compiler vval_ is not a dependent name, so it will try to look it up before the actual instantiation of the template with the type. At that point, the base type is not yet known to the compiler [*], and thus it does not consider the templated bases. Visual Studio does not perform the two phase lookup, and thus this is not required there.

解决方案是将标识符转换为从属标识符,这可以通过多种方式之一来完成.最简单和推荐的方法是使用this(与this->vval_相同).通过添加显式的this,编译器知道vval_可以根据模板参数而有所不同,现在它是一个依赖名称,并且将查找推迟到第二阶段(在参数替换之后)

The solution is transforming the identifier into a dependent identifier, which can be done in one of multiple ways. The simplest and recommended would be using this (as in this->vval_). By adding the explicit this, the compiler knows that vval_ can differ depending on the template arguments, it is now a dependent name, and it postpones lookup to the second phase (after argument substitution).

或者,您可以使用TestImpl<T>::vval_来限定标识符所属的类型(如@mrozenau所建议).同样,这使标识符依赖于模板参数T并推迟了查找.尽管它们都具有将查找推迟到以后的最终目的,但是第二种方法具有额外的副作用,即动态分配将被禁用.在这种特殊情况下,没有关系,但是如果vval_实际上是一个虚函数,则this->f()将调用最终的替代程序,而TestImpl<T>::f()将执行TestImpl<T>中存在的替代程序.

Alternatively, you can qualify the type that the identifier belongs to, as @mrozenau suggests, by using TestImpl<T>::vval_. Again that makes the identifier dependent on the template argument T and lookup is postponed. While both of them serve the ultimate purpose of postponing the lookup to a later time, this second approach has the extra side effect that dynamic dispatch will be disabled. In this particular case it does not matter, but if vval_ was actually a virtual function then this->f() would call the final overrider, while TestImpl<T>::f() would execute the overrider present in TestImpl<T>.

[*] 在模板的第一阶段验证期间,在将参数替换为模板之前,尚不知道基本类型.这样做的原因是,不同的参数集可能会触发对基本模板不同专业化的选择.

[*] During the first phase verification of templates, before the arguments are substituted into the template, the base type is not yet known. The reason for this is that different sets of arguments might trigger the selection of different specializations of the base template.

这篇关于模板类与私有继承的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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