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

Evi*_*ael 7 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;
}
Run Code Online (Sandbox Code Playgroud)

我想知道为什么我可以get<0>()从main函数访问该方法

a.get<0>() = 5;
Run Code Online (Sandbox Code Playgroud)

但不是从A& getVal0()方法中:

error: 'get' was not declared in this scope
Run Code Online (Sandbox Code Playgroud)

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

return boost::tuple<A>::get<0>();
Run Code Online (Sandbox Code Playgroud)

这会产生不同的错误

error: expected primary-expression before ')' token
Run Code Online (Sandbox Code Playgroud)

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

在boost文档中是Visual C++的注意事项

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

但我正在使用GCC 4.5.2和4.8.1

提前致谢

Die*_*ühl 5

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

this->template get<0>()
Run Code Online (Sandbox Code Playgroud)

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

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

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