0

只是一个示例代码:

template <class T> class TempBase
{
protected:
  string m_str;
};

template <class T> class Temp: public TempBase<T>
{
public:
  void method()
  {
    string
        &s = TempBase<T>::m_str //reference works fine
        /*NOTE compile failed:
        error: ‘std::string TempBase<int>::m_str’ is protected
        error: within this context
        error: cannot convert ‘std::string TempBase<int>::* {aka std::basic_string<char> TempBase<int>::*}’ to ‘std::string* {aka std::basic_string<char>*}’ in initialization
        */
      , *ps = &TempBase<T>::m_str 
      , *ps2 = &m_str //compile failed, obviously: ‘m_str’ was not declared in this scope
      , *ps3 = &s //this is workaround, works fine
    ;
  }
};

void f()
{
  Temp<int> t;
  t.method();
}

std::string *目标:具有祖先成员的类型的初始化指针TempBase<T>::m_str

问题:正确的语法未知

评论:之前的代码包含 2 个故意的编译错误:

  1. 尝试将成员指针转换为数据指针
  2. 模板祖先成员必须完全合格

和 1 个解决方法。

问题:在这种情况下,获取指向祖先数据的指针的正确语法是什么?

4

2 回答 2

2

我将假设解决方法最好地描述了您想要的行为

&s = TempBase<T>::m_str;

(您在问题中提供)而不是解决方法

&s = this->m_str;

在您的示例中也可以。

解决方案:&(TempBase::m_str)

原因:TempBase::m_str 是一个合格的 id,(TempBase::m_str) 不是。

代码示例:

#include <iostream>
#include <string>

using namespace std;

template <class T> class TempBase
{
protected:
  string m_str;
};

template <class T> class Temp: public TempBase<T>
{
public:
  void method()
  {
    string* ps3 = &(TempBase<T>::m_str); //this is workaround, works fine
    (*ps3) += "ciao";
    cout << *ps3 << endl;
  }
};

void f()
{
  Temp<int> t;
  t.method();
}

int main( int argc, char* argv[] ) 
{
    f();

}

你可以在这里试试

于 2013-09-18T09:09:02.380 回答
1

&m_str不起作用的原因:[temp.dep]/3

在类或类模板的定义中,如果基类依赖于模板参数,则在非限定名称查找期间不会检查基类范围 [...]

但是,this->m_str表示从属名称(因为this根据 [temp.dep.expr]/2 是从属的)。在这种情况下,使用依赖名称查找,它找到基类成员。

如果我们在类范围之外添加模板的特化和名称,问题会更加明显:

string m_str;

template<class T> struct A { string m_str; };
template<> struct A<int> { /* no member */ };

template<class T> struct B : A
{
    void foo() { m_str = "hello"; }
};

B<int>().foo();    // clearly modifies the global `m_str`
B<double>().foo(); // modifies what?

如果搜索了基类范围,则在实例化之前(在知道模板参数之前)将不知道m_str所指的内容。此外,这很容易导致意想不到的结果。

因此,不会搜索基类范围(如果基类是依赖的并且我们处于“模板上下文”中)。


起作用的原因&s = TempBase<T>::m_str

id-expression 使用TempBase<T>::m_strqualified-id,因此TempBase<T>搜索范围并m_str找到成员。


&TempBase<T>::m_str不起作用的原因,但&(TempBase<T>::m_str)确实:[expr.unary.op]/3

一元运算符的结果&是指向其操作数的指针。操作数应该是一个左值或一个qualified-id。如果操作数是用 type命名某个类的非静态成员的限定 ID,则结果具有类型“指向类型的成员的指针”并且是指定的纯右值。否则,如果表达式的类型是,则结果的类型为“指向”,并且是一个纯右值,即指定对象 (1.7) 的地址或指向指定函数的指针。mCTCTC::mTT

paranthesized 表达式(TempBase<T>::m_str)不是限定 ID,因此&(TempBase<T>::m_str)不会形成指向成员的指针,而是指向由 . 表示的对象的普通指针(TempBase<T>::m_str)

于 2013-09-18T09:54:36.977 回答