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 *目標:祖先 member を持つ型の init ポインターTempBase<T>::m_str

問題: 正しい構文が不明

コメント: 前のコードには 2 つの意図的なコンパイル エラーが含まれています。

  1. メンバ ポインタをデータ ポインタに変換しようとしています
  2. テンプレート化された祖先メンバーは完全に修飾されている必要があります

そして1つの回避策。

質問: この場合、祖先データへのポインターを取得するための正しい構文は何ですか?

4

2 に答える 2

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修飾された idを使用しているため、 のスコープTempBase<T>が検索され、メンバーm_strが見つかります。


&TempBase<T>::m_str機能しない理由&(TempBase<T>::m_str): [expr.unary.op]/3

単項演算子の結果は、&そのオペランドへのポインターです。オペランドは、左辺値または修飾 IDでなければなりません。オペランドがtype を持つクラスの非静的メンバーを指定する修飾 IDである場合、結果の型は「type のクラスのメンバーへのポインター」であり、 を指定する prvalueです。それ以外の場合、式の型が の場合、結果は型「へのポインター」を持ち、指定されたオブジェクトのアドレス (1.7) または指定された関数へのポインターである prvalue になります。mCTCTC::mTT

括弧で囲まれた式(TempBase<T>::m_str)修飾 IDではないため&(TempBase<T>::m_str)、メンバーへのポインターを形成しませんが、 で示されるオブジェクトへの通常のポインターを形成します(TempBase<T>::m_str)

于 2013-09-18T09:54:36.977 に答える