7

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

我尝试从 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<0>(*this) 有效。这种解决方法对我来说没问题。但是我仍然想知道为什么我现在不能使用 tuple 方法。

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

笔记!MS Visual C++ 编译器不支持成员 get 函数。此外,编译器很难找到没有显式命名空间限定符的非成员 get 函数。因此,在编写应使用 MSVC++ 6.0 编译的代码时,所有 get 调用都应限定为:tuples::get(a_tuple)。

但我使用的是 GCC 4.5.2 和 4.8.1

提前致谢

4

1 回答 1

5

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

this->template get<0>()

需要该this部分来使其成为依赖查找(您也可以使用适当的类限定,但这有点麻烦且不必要,除非您隐藏了基类名称)。该template部分是告诉编译器依赖名称 ( get) 恰好是模板所必需的。

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

  • 任何不立即依赖于某种形式的模板参数的名称仅在第一阶段查找,即在定义模板的上下文中。由于模板参数是未知的,因此基类的确切布局是未知的(它可能是专门的),基类中的任何名称都将被忽略。使用任何导致名称依赖于模板参数的限定条件,例如使用this->,将查找移动到第二阶段,即,当模板被实例化时。
  • <一旦名称依赖,如果在第一阶段解析模板时表达式涉及字符,即当模板参数尚不知道时,则会出现歧义:<可以是显式模板参数的开始成员函数调用或者它可以是小于运算符。由于很少明确提及模板参数(好吧,至少在制定这些规则时很少见),因此默认情况下它被假定为小于运算符。要声明该名称实际上是一个具有显式指定模板参数的成员函数模板,它需要在其前面加上关键字template(非常类似于需要 a 的类型typename)。
于 2013-11-24T20:48:42.853 回答