派生对基类成员数据的模板类访问

Sha*_*ter 60 c++ inheritance templates scope name-lookup

这个问题是一个在问的赞助这个线程.

使用以下类定义:

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!
}
Run Code Online (Sandbox Code Playgroud)

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

编辑:

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

sth*_*sth 64

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

void Bar<T>::BarFunc () {
    std::cout << this->_foo_arg << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

或者你也可以using在方法中使用" ":

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

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

  • Faq的链接非常有用:它还显示此问题可能会导致不必要的行为. (3认同)
  • 任何想法*为什么*这是真的?(FAQ没有完全回答这个问题) (3认同)

son*_*yao 23

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

要更正代码,只需使名称_foo_arg相关即可,因为只能在实例化时查找依赖名称,并且在那时必须知道必须探索的确切基本特化.例如:

// solution#1
std::cout << this->_foo_arg << std::endl;
Run Code Online (Sandbox Code Playgroud)

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

// solution#2
std::cout << Foo<T>::_foo_arg << std::endl;
Run Code Online (Sandbox Code Playgroud)

必须小心使用此解决方案,因为如果使用非限定非依赖名称来形成虚函数调用,则限定禁止虚拟调用机制并且程序的含义发生变化.

并且您可以通过以下方式从派生类中的依赖基类中引入名称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
}
Run Code Online (Sandbox Code Playgroud)