2010-10-24 69 views
29

为什么不能将C++编译器识别g()b被继承的Superclass成员在此代码所示:访问超类的保护成员在C++中使用模板

template<typename T> struct Superclass { 
protected: 
    int b; 
    void g() {} 
}; 

template<typename T> struct Subclass : public Superclass<T> { 
    void f() { 
    g(); // compiler error: uncategorized 
    b = 3; // compiler error: unrecognized 
    } 
}; 

如果我简化Subclass和刚刚继承然后它编译。当完全符合g()时,它也编译为Superclass<T>::g()Superclass<T>::b。我正在使用LLVM GCC 4.2。

注意:如果我在超类中公开g()b,它仍会失败并出现相同的错误。或者

template<typename T> struct Subclass : public Superclass<T> { 
    void f() { 
    this->g(); 
    this->b = 3; 
    } 
}; 

,正如你:

回答

39

这可以通过使用using拉的名字到当前范围修改为:

template<typename T> struct Subclass : public Superclass<T> { 
    using Superclass<T>::b; 
    using Superclass<T>::g; 

    void f() { 
    g(); 
    b = 3; 
    } 
}; 

或通过该0​​指针访问限定名称已经注意到,通过限定全名。

这是必要的原因是,C++不考虑名称解析的超类模板(因为它们是从属名称和从属名称不予考虑)。它在您使用Superclass<int>时起作用,因为它不是模板(它是实例化模板),因此它的嵌套名称不是,而是依赖于的名称。

+6

微软的编译器不服从这条规则。我很生气 – 2010-10-24 21:06:24

+0

谢谢,那有效。 – andrewz 2010-10-25 00:44:11

+8

@阿门:只有这一个规则?哇,它真的*变得更好了。 :-D – 2010-10-25 06:04:18

14

Konrad的回答并没有要求或回答最终的“为什么”。这不仅仅是C++委员会任意说“嘿,放弃依赖名字,反正没有人喜欢它们”。相反,编译器甚至在实例化之前对模板进行了一些检查,并且直到它知道T之前,它才具有g()或b的意义,因为它通常不能 - 通常 - 在可能的特化之间进行选择基类(例如SuperClass<X>可能有int b,而SuperClass<Y>void b()SuperClass<Z>根本没有b)。更明确的形式只是说“相信我 - 在实例化时它必须来自基类”(否则会出现编译器错误)“。

+0

有点有道理,但它绝对是模板的一个比较模糊的“特征”。 – ChrisWue 2014-01-08 22:06:22

+0

@ChrisWue:这场比赛有很多比赛! ;-) – 2014-01-09 02:47:23

+0

GCC能够在过去的20世纪90年代处理这个问题,但随着C++的发展,它发生了变化。我认为在某些情况下处理它的方式会造成问题,这就是为什么它发生了变化。 – PolarBear2015 2017-02-06 14:32:28