为什么涉及模板类时,派生类无法访问基础函数?

8
以下代码会出现编译错误:
template <typename T>
class Base
{
    public:
    void bar(){};
};

template <typename T>
class Derived : public Base<T>
{
    public:
    void foo() { bar(); }   //Error
};

int main()
{
    Derived *b = new Derived;
    b->foo();
}

错误

第12行:错误:没有模板参数依赖于“bar”的参数,因此必须提供“bar”的声明

为什么会出现这个错误?


作为一则附注:您在main()中没有为Derived指定模板参数。 - Nobody moving away from SE
2个回答

14
名称foo()不依赖于任何Derived的模板参数——它是一个非相关名称。另一方面,找到foo()的基类Base<T>——确实依赖于Derived的一个模板参数(即T),因此它是一个相关基类。C ++在查找非相关名称时不会查找相关基类。
为了解决这个问题,您需要将Derived::foo()中对bar()的调用限定为this->bar()Base<T>::bar()
这个C ++ FAQ项目解释得很好:请参见http://www.parashift.com/c++-faq-lite/templates.html#faq-35.19

我一直认为这是C++的一个短板。在Python中,额外的修饰符self.在属性和方法前面可能看起来有点啰嗦,但它是一致的,因此人们习惯了它。在C ++中,this->是可选的......所以人们会忘记什么时候真正需要它......所有这些都是为了节省5个字符:x。 - Matthieu M.
1
哦,我并不是在抨击模板机制。我是在抨击语法上的不一致性。有时候需要使用 this-> 是很难理解的。而且想象一下,如果你有一个名为 bar 的自由函数会发生什么?它会被捕捉到,即使在类中通常方法优先于自由函数。我的观点是,要求 对所有方法调用都使用 this-> 将会产生更加规范的语法。 - Matthieu M.
@litb:你能举一个合格但非依赖的名称的例子,它在依赖的基类中被查找吗? - HighCommander4
使用限定名在依赖的基类中查找某些内容,本身就使名称变得不确定。所以不存在你要求的例子。但是,如果等到实例化时再进行非依赖未限定名称的查找,则可能可以查找依赖的基类。然而,标准规定非依赖名称的绑定必须在解析时固定。因此,如果没有这样一个规则,即未限定名称不会在依赖基类中查找,那么你将面临一种典型的未定义行为情况,因为行为描述被省略了。 - Johannes Schaub - litb
请注意,在解析时已知绑定并不意味着忽略依赖的基类。这可能意味着在替换依赖的基类之前无法查找依赖的基类,因此需要发出诊断信息。 - Johannes Schaub - litb
显示剩余7条评论

0

您提供的代码在您指示的行上没有构建错误。但是它在这里有一个:

Derived *b = new Derived;

应该是这样写的:

Derived<int> *b = new Derived<int>();

(或者使用任何你想要的类型,而不是int。)


它确实在OP所说的那一行有一个错误,以及你指出的错误。 - juanchopanza
@cppcoder 好吧,它解决了一个问题。至于上面答案中提到的资格条件,看起来你的编译器比我的更愚蠢/更兼容/更挑剔! :-) - Grimm The Opiner
1
@user1158692:更加符合规范是正确的选择。为了符合规范,编译器必须对那个未经限定的对bar()的引用进行报错。 - David Hammen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接