如何将init指针指向模板化祖先的数据

时间:2013-09-18 08:58:56

标签: c++ templates

只是示例代码:

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. 模板化的祖先成员必须是完全合格的
  3. 和1种解决方法。

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

2 个答案:

答案 0 :(得分:2)

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

&s = TempBase<T>::m_str;

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

&s = this->m_str;

在你的例子中也会起作用。

解决方案:&amp;(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();

}

您可以尝试here

答案 1 :(得分:1)

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

  

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

但是,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_str正在使用 qualified-id ,因此会搜索TempBase<T>的范围并且成员{{1找到了。


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

  

一元&(TempBase<T>::m_str)运算符的结果是指向其操作数的指针。操作数应为左值或 qualified-id 。如果操作数是 qualified-id ,则命名类型为&的某个类m的非静态成员C,结果的类型为“指向成员的指针属于T类的C类,并且是指定T的prvalue。否则,如果是类型   表达式为C::m,结果具有类型“指向T的指针”,并且是一个prvalue,它是指定对象的地址(1.7)或指向指定函数的指针。

paranthesized表达式T不是 qualified-id ,因此(TempBase<T>::m_str)不会形成指向成员的指针,而是指向对象的普通指针&(TempBase<T>::m_str)