C ++无法从派生类中调用基类方法

时间:2013-11-24 20:40:05

标签: c++ boost boost-tuples

这是我的第一个问题,我希望我做的一切都是正确的。

我尝试从boost元组派生一个类。 Boost的元组提供了一个get()模板方法来访问各个字段。有趣的是,我不能在派生类中使用该方法。

以下代码显示了问题:

#include <iostream>
#include <boost/tuple/tuple.hpp>
using namespace std;

template<typename A>
class Derived : public boost::tuple<A>
{
public:
    Derived() : boost::tuple<A>() {}

    A& getVal0()
    {
        return get<0>();
        // does not compile:
        //error: 'get' was not declared in this scope

        return boost::tuple<A>::get<0>();
        // does not compile
        //error: expected primary-expression before ')' token

        return boost::tuples::get<0>(*this);
        //works
    }
};  

int main() {
    Derived<int> a;

    a.get<0>() = 5;

    cout << a.get<0>() << endl; 
    cout << a.getVal0() << endl; 
    return 0;
}

我想知道为什么我可以从主函数

访问get<0>()方法
a.get<0>() = 5;

但不是来自A& getVal0()方法:

error: 'get' was not declared in this scope

第二个返回行是我尝试将方法调用的范围限定为基类:

return boost::tuple<A>::get<0>();

这会产生不同的错误

error: expected primary-expression before ')' token

调用外部函数`boost :: tuples :: get&lt; 0&gt;(* this)有效。这个解决方法对我来说没问题。但我仍然想知道为什么我不能在这一点上使用元组方法。

在boost文档中是Visual C ++的通知

  

请注意! MS Visual C ++编译器不支持成员获取函数。此外,编译器在没有显式名称空间限定符的情况下找到非成员get函数时遇到问题。因此,在编写应该使用MSVC ++ 6.0编译的代码时,所有get调用都应该被限定为:tuples :: get(a_tuple)。

但我正在使用GCC 4.5.2&amp; 4.8.1

提前致谢

1 个答案:

答案 0 :(得分:5)

假设基类中有一个get<I>()成员函数模板,您可能想要使用

this->template get<0>()

需要this部分才能使其成为依赖查找(您也可以使用适当的类限定,但除非您隐藏基类名称,否则这有点痛苦和不必要)。 template部分是告诉编译器依赖名称(get)碰巧是模板所必需的。

需要this(或其他一些限定条件)和template的主要原因是模板的两阶段编译模型:

  • 仅在阶段I期间,即在定义模板的上下文中查找任何不立即依赖于某种形式的模板参数的名称。由于模板参数是未知的,因此,基类的确切布局未知(可能是专用的),基类中的任何名称都将被忽略。使用导致名称依赖于模板参数的任何限定条件,例如,使用this->,将查找移动到阶段II,即,当模板被实例化时。
  • 一旦名称依赖,如果表达式涉及<字符,而模板在阶段I中被解析,即当模板参数尚未知道时,则会产生歧义:{{1}可以是成员函数调用的显式模板参数的开头,也可以是小于运算符。由于明确提到模板参数很少(嗯,至少在制定这些规则时很少见),默认情况下假定它是小于运算符。要声明该名称实际上是具有明确指定的模板参数的成员函数模板,则需要在其前面加上关键字<(非常类似于需要template的类型)。