模版类继承需显示声明子类成员

作者: , 共 1594 字 , 共阅读 0

在 gcc 中,存在继承关系的模版类,子类无法直接访问父类的成员,即使该成员是protectedpublic

1、一个简单的例子

#include <iostream> 

template <class  T>
class Base {
public:
    T x;
    Base(T _x) : x(_x) {}
};

template <class T>
class Derived : public Base<T> {
public: 
    Derived(T x) : Base<T>(x) {}
    void log() { 
        std::cout << x << std::endl; 
    }
};

int main()
{
    Derived<int> d(2);
    d.log();
}

gcc编译下会报错:

In member function 'void Derived::log()': 16:22: error: 'x' was not declared in this scope

而且这个错误只会在gcc下出现,vc不会出现该问题。因此,编写跨平台的模版库时,应当去gcc下编译。

另外,这个错误只有在DerivedBase都是模版类时才会出现,这两者任何一个不是模版类,都不会出现编译错误。

2、原因

原因据说是因为stdandard 14.6/8

When looking for the declaration of a name used in a template definition, the usual lookup rules (3.4.1, 3.4.2) are used for nondependent names. The lookup of names dependent on the template parameters is postponed until the actual template argument is known (14.6.2).

stdandard 16.2是这么说的:

In the definition of a class template or a member of a class template, if a base class of the class template depends on a template-parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member.

也就是说gcc的编译报错行为符合c++标准。

3、解决方案

3.1、通过子类引用

void log() {
    std::cout << Base<T>::x << std::endl; 
}

3.2、通过 this 引用

void log() {
    std::cout << this->x << std::endl;
}

3.3、通过 using 将变量引入子类

using Base<T>::x;
void log() {
    std::cout << x << std::endl;
}

Q. E. D.

类似文章:
编程 » C++, C++标准库
std::tuple的原理并不复杂,但有些细节非常有意思。其中有一个是至少在gnu C++ std的实现中,std::tuple是倒序存储的:
编程 » C++, 智能指针
理论上而言,当 C++提供了std::unique_ptr, C++的程序就不应该出现普通指针了。所有普通指针都可以用std::unique_ptr代替,避免手动删除对象。
Pyhon 的抽象基类( abstruct base class )库abc定义了类似于 C++的纯虚函数的功能:
智能指针在现代 C++里用得越多。以前只知道它大致的原理,比如使用引用计数。但很多实现细节并不清楚,最直接的,它是如何实现多线程安全的?今天找了 gnu c++ library 的实现好好看了一下。
编程 » C++, 异步
C++11 的标准异步库至少包含下面内容:
编程 » C++, Boost, 智能指针
如果理解了侵入式容器,侵入式智能指针也很容易理解。传统的智能指针std::shared_ptr使用了和数据无关的引用计数,这带来两个问题:
编程 » C++, 智能指针
前面已经提到std::shared_ptr有三个缺陷:
编程 » C++, 编译
一个典型的 GCC C++编译过程为:
出现的一个场景是将函数指针用 void
编程 » C++, C++11
花括号初始化是C++11引入的一种初始化方法。
编程 » C++
C++的浮点数转整数有四种方法,直接类型转换、round、floor、ceil。其效果如下表:
最近老遇到一个奇怪的问题。在 VS 2013 编译时,爆出很多警告: