77

这个问题是对这个线程中提出的问题的推进。

使用以下类定义:

template <class T>
class Foo {

public:
    Foo (const foo_arg_t foo_arg) : _foo_arg(foo_arg)
    {
        /* do something for foo */
    }
    T Foo_T;        // either a TypeA or a TypeB - TBD
    foo_arg_t _foo_arg;
};

template <class T>
class Bar : public Foo<T> {
public:
    Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
    : Foo<T>(bar_arg)   // base-class initializer
    {

        Foo<T>::Foo_T = T(a_arg);
    }

    Bar (const foo_arg_t bar_arg, const b_arg_t b_arg)
    : Foo<T>(bar_arg)
    {
        Foo<T>::Foo_T = T(b_arg);
    }

    void BarFunc ();

};

template <class T>
void Bar<T>::BarFunc () {
    std::cout << _foo_arg << std::endl;   // This doesn't work - compiler error is: error: ‘_foo_arg’ was not declared in this scope
    std::cout << Bar<T>::_foo_arg << std::endl;   // This works!
}

在访问模板类基类的成员时,似乎我必须始终使用Bar<T>::_foo_arg. 有没有办法避免这种情况?'using' 语句/指令能否在模板类方法中发挥作用以简化代码?

编辑:

通过使用 this-> 语法限定变量来解决范围问题。

4

3 回答 3

89

您可以使用this->来明确您指的是班级的成员:

void Bar<T>::BarFunc () {
    std::cout << this->_foo_arg << std::endl;
}

或者,您也可以using在方法中使用“”:

void Bar<T>::BarFunc () {
    using Bar<T>::_foo_arg;             // Might not work in g++, IIRC
    std::cout << _foo_arg << std::endl;
}

这使编译器清楚地知道成员名称取决于模板参数,以便它在正确的位置搜索该名称的定义。有关详细信息,另请参阅C++ Faq Lite 中的此条目

于 2009-07-13T17:50:19.910 回答
29

这里的基类不是一个不依赖的基类(这意味着一个具有可以在不知道模板参数的情况下确定的完整类型的基类),并且_foo_arg是一个不依赖的名称。标准 C++ 说,不依赖的名称不在依赖的基类中查找。

为了更正代码,使名称_foo_arg依赖就足够了,因为依赖名称只能在实例化时查找,并且那时必须探索的确切基本专业化将是已知的。例如:

// solution#1
std::cout << this->_foo_arg << std::endl;

另一种方法是使用限定名称引入依赖项:

// solution#2
std::cout << Foo<T>::_foo_arg << std::endl;

必须注意这种解决方案,因为如果使用非限定的非依赖名称来形成虚函数调用,那么限定会抑制虚调用机制并且程序的含义会发生变化。

您可以通过以下方式从派生类中的依赖基类中获取名称using

// solution#3
template <class T>
class Bar : public Foo<T> {
public:
    ...
    void BarFunc ();
private:
    using Foo<T>::_foo_arg;
};

template <class T>
void Bar<T>::BarFunc () {
    std::cout << _foo_arg << std::endl;   // works
}
于 2014-06-23T14:33:48.927 回答
1

在 Visual C++ 2008 中似乎可以正常工作。我为您提到的类型添加了一些虚拟定义,但没有提供任何来源。其余的和你说的完全一样。然后是强制BarFunc实例化和调用的主函数。

#include <iostream>

class streamable {};
std::ostream &operator<<(std::ostream &os, streamable &s) { return os; }

class foo_arg_t : public streamable {};
class a_arg_t : public streamable {};
class b_arg_t : public streamable  {};

template <class T>
class Foo {

public:
    Foo (const foo_arg_t foo_arg) : _foo_arg(foo_arg)
    {
        /* do something for foo */
    }
    T Foo_T;        // either a TypeA or a TypeB - TBD
    foo_arg_t _foo_arg;
};

template <class T>
class Bar : public Foo<T> {
public:
    Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
    : Foo<T>(bar_arg)   // base-class initializer
    {

        Foo<T>::Foo_T = T(a_arg);
    }

    Bar (const foo_arg_t bar_arg, const b_arg_t b_arg)
    : Foo<T>(bar_arg)
    {
        Foo<T>::Foo_T = T(b_arg);
    }

    void BarFunc ();

};

template <class T>
void Bar<T>::BarFunc () {
    std::cout << _foo_arg << std::endl; 
    std::cout << Bar<T>::_foo_arg << std::endl;   
}

int main()
{
    Bar<a_arg_t> *b = new Bar<a_arg_t>(foo_arg_t(), a_arg_t());
    b->BarFunc();
}
于 2009-07-13T17:31:03.180 回答