このポインタを介してテンプレートの基本クラスメンバーにアクセスする必要があるのはなぜですか?

211
Ali 2011-01-10 15:42.

以下のクラスはテンプレートでなかった場合、私は単に持っている可能性がxderivedクラス。ただし、以下のコードでは、を使用する必要がありますthis->x。どうして?

template <typename T>
class base {

protected:
    int x;
};

template <typename T>
class derived : public base<T> {

public:
    int f() { return this->x; }
};

int main() {
    derived<int> d;
    d.f();
    return 0;
}

3 answers

290
Steve Jessop 2011-01-10 16:44.

簡単な答え:x依存する名前を作成するため。テンプレートパラメーターがわかるまでルックアップが延期されます。

長い答え:コンパイラがテンプレートを見ると、テンプレートパラメータを見ずに、特定のチェックをすぐに実行することになっています。その他は、パラメーターがわかるまで延期されます。これは2フェーズコンパイルと呼ばれ、MSVCはそれを行いませんが、標準で必要とされ、他の主要なコンパイラーによって実装されます。必要に応じて、コンパイラーはテンプレートを(ある種の内部解析ツリー表現に)認識したらすぐにコンパイルし、インスタンス化のコンパイルを後で行う必要があります。

テンプレートの特定のインスタンス化ではなく、テンプレート自体に対して実行されるチェックでは、コンパイラーがテンプレート内のコードの文法を解決できる必要があります。

C ++(およびC)では、コードの文法を解決するために、何かが型であるかどうかを知る必要がある場合があります。例えば:

#if WANT_POINTER
    typedef int A;
#else
    int A;
#endif
static const int x = 2;
template <typename T> void foo() { A *x = 0; }

Aが型の場合、ポインタを宣言します(グローバルをシャドウイングする以外の効果はありませんx)。Aがオブジェクトの場合、それは乗算です(そして、演算子のオーバーロードを除いて、それは違法であり、右辺値に割り当てます)。間違っている場合、このエラーはフェーズ1で診断する必要があります。これは、特定のインスタンス化ではなく、テンプレートのエラーであると標準で定義されています。テンプレートがインスタンス化されない場合でも、Aがintthenの場合、上記のコードは形式が正しくfooないため、テンプレートではなく単純な関数である場合と同様に、診断する必要があります。

現在、標準では、テンプレートパラメータに依存しない名前、フェーズ1Aで解決可能である必要があるとされています。これは依存名ではなく、タイプに関係なく同じものを参照しTます。したがって、フェーズ1で見つけてチェックするには、テンプレートを定義する前に定義する必要があります。

T::ATに依存する名前になります。フェーズ1では、それがタイプであるかどうかを知ることはできません。最終的にTインスタンス化のように使用されるタイプはまだ定義されていない可能性が高く、たとえ定義されていたとしても、テンプレートパラメータとして使用されるタイプがわかりません。ただし、不正なテンプレートの貴重なフェーズ1チェックを実行するには、文法を解決する必要があります。したがって、標準には従属名の規則があります。コンパイラーはtypename、それら型であることを指定する資格がない限り、または特定の明確なコンテキストで使用されない限り、それらが非型であると想定する必要があります。たとえば、ではtemplate <typename T> struct Foo : T::A {};T::Aは基本クラスとして使用されるため、明確に型になります。ネストされたタイプAではなくFooデータメンバーを持つタイプでインスタンス化された場合、それはインスタンス化をA実行するコードのエラー(フェーズ2)であり、テンプレートのエラー(フェーズ1)ではありません。

しかし、依存する基本クラスを持つクラステンプレートはどうですか?

template <typename T>
struct Foo : Bar<T> {
    Foo() { A *x = 0; }
};

Aは従属名ですか?基本クラスでは、任意の名前が基本クラスに表示される可能性があります。したがって、Aは従属名であると言え、非型として扱うことができます。これは、Fooのすべての名前が依存しているという望ましくない影響を与えるため、Fooで使用されるすべての型(組み込み型を除く)を修飾する必要があります。Fooの内部では、次のように書く必要があります。

typename std::string s = "hello, world";

なぜならstd::string依存名で、従って、特に断りのない限り、非タイプであると仮定なります。痛い!

優先コード(return x;)を許可する際の2番目の問題は、Barが以前Fooに定義されてxいて、その定義のメンバーではない場合でも、誰かが後でデータメンバーを持つような、Barあるタイプの特殊化を定義してからインスタンス化できることです。。したがって、そのインスタンス化では、テンプレートはグローバルを返す代わりにデータメンバーを返します。または逆に、のベーステンプレート定義がhadの場合、それなしでスペシャライゼーションを定義でき、テンプレートはで返されるグローバルを検索します。これはあなたが抱えている問題と同じように驚くべき苦痛であると判断されたと思いますが、驚くべきエラーを投げるのではなく、静かに驚くべきことです。BazBar<Baz>xFoo<Baz>xBarxxFoo<Baz>

これらの問題を回避するために、実際の標準では、クラステンプレートの依存する基本クラスは、明示的に要求されない限り、検索の対象とは見なされません。これにより、依存ベースで見つかる可能性があるという理由だけで、すべてが依存するのを防ぎます。それはまたあなたが見ている望ましくない効果を持っています-あなたは基本クラスからのものを修飾しなければなりません、さもなければそれは見つかりません。A依存させる一般的な方法は3つあります。

  • using Bar<T>::A;クラス内-A現在、の何かを参照しているBar<T>ため、依存しています。
  • Bar<T>::A *x = 0;使用時点で-繰り返しますが、A間違いなくにありBar<T>ます。これはtypename使用されなかったため乗算であるため、おそらく悪い例ですが、インスタンス化まで待ってoperator*(Bar<T>::A, x)、右辺値が返されるかどうかを確認する必要があります。誰が知っている、多分それは...
  • this->A;使用時点で-Aはメンバーであるため、に含まれていない場合Fooは基本クラスに含まれている必要があります。これも標準で依存しているとされています。

2フェーズのコンパイルは面倒で困難であり、コードに余分な冗長性を持たせるための驚くべき要件がいくつかあります。しかし、民主主義のように、他のすべての方法を除けば、それはおそらく物事を行うための最悪の方法です。

あなたの例でreturn x;x、が基本クラスのネストされた型であるかどうかは意味がないので、言語は(a)従属名であると言い、(2)それを非型として扱い、あなたのコードはthis->。なしで動作します。あなたはあなたのケースには当てはまらない問題の解決策からの巻き添え被害の犠牲者ですが、それでもあなたの基本クラスがあなたの下にグローバルを隠す名前を導入する可能性がある、またはあなたが思った名前を持っていないという問題があります彼らは持っていました、そして代わりにグローバルが見つかりました。

また、デフォルトは依存名の反対である必要がある(オブジェクトとして指定されていない限りタイプを想定する)、またはデフォルトはより文脈依存である必要がある(ではstd::string s = "";std::string他に文法的なものがないため、タイプとして読み取ることができる)と主張することもできます。std::string *s = 0;あいまいですが、意味があります)。繰り返しになりますが、ルールがどのように合意されたかはよくわかりません。私の推測では、必要となるテキストのページ数は、コンテキストが型をとる、および型をとらない特定のルールを多数作成することを軽減したと思います。

13
Ali 2011-01-10 15:48.

(2011年1月10日からの元の回答)

私は答えを見つけたと思います:GCCの問題:テンプレート引数に依存する基本クラスのメンバーを使用します。答えはgccに固有のものではありません。


更新:mmichaelのコメントに応えて、C ++ 11標準のドラフトN3337から:

14.6.2依存名[temp.dep]
[...]
3クラスまたはクラステンプレートの定義で、基本クラスがテンプレートパラメータに依存している場合、非修飾名のルックアップ中に基本クラスのスコープは検査されません。クラステンプレートまたはメンバーの定義ポイント、またはクラステンプレートまたはメンバーのインスタンス化中。

「規格がそう言っているから」が答えとしてカウントされるかどうかはわかりません。なぜ標準がそれを義務付けているのかを尋ねることができますが、Steve Jessopの優れた回答や他の人が指摘しているように、この後者の質問に対する回答はかなり長く、議論の余地があります。残念ながら、C ++標準に関しては、標準が何かを義務付けている理由について、簡潔で自己完結型の説明をすることはほとんど不可能です。これは後者の質問にも当てはまります。

11
chrisaycock 2011-01-10 15:47.

x相続時に隠されています。次の方法で再表示できます。

template <typename T>
class derived : public base<T> {

public:
    using base<T>::x;             // added "using" statement
    int f() { return x; }
};

Related questions

MORE COOL STUFF

Reba McEntire は、彼女が息子の Shelby Blackstock と共有する「楽しい」クリスマスの伝統を明らかにしました:「私たちはたくさん笑います」

Reba McEntire は、彼女が息子の Shelby Blackstock と共有する「楽しい」クリスマスの伝統を明らかにしました:「私たちはたくさん笑います」

Reba McEntire が息子の Shelby Blackstock と共有しているクリスマスの伝統について学びましょう。

メーガン・マークルは、自然な髪のスタイリングをめぐってマライア・キャリーと結ばれました

メーガン・マークルは、自然な髪のスタイリングをめぐってマライア・キャリーと結ばれました

メーガン・マークルとマライア・キャリーが自然な髪の上でどのように結合したかについて、メーガンの「アーキタイプ」ポッドキャストのエピソードで学びましょう.

ハリー王子は家族との関係を修復できるという「希望を持っている」:「彼は父親と兄弟を愛している」

ハリー王子は家族との関係を修復できるという「希望を持っている」:「彼は父親と兄弟を愛している」

ハリー王子が家族、特にチャールズ王とウィリアム王子との関係について望んでいると主張したある情報源を発見してください。

ワイノナ・ジャッドは、パニックに陥った休暇の瞬間に、彼女がジャッド家の家長であることを認識しました

ワイノナ・ジャッドは、パニックに陥った休暇の瞬間に、彼女がジャッド家の家長であることを認識しました

ワイノナ・ジャッドが、母親のナオミ・ジャッドが亡くなってから初めての感謝祭のお祝いを主催しているときに、彼女が今では家長であることをどのように認識したかを学びましょう.

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セント ヘレナ島のジェイコブズ ラダーは 699 段の真っ直ぐ上る階段で、頂上に到達すると証明書が発行されるほどの難易度です。

The Secrets of Airline Travel Quiz

The Secrets of Airline Travel Quiz

Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

スタートレックの50周年を称えるための最良の方法

スタートレックの50周年を称えるための最良の方法

来年は、スペースオペラの最も壮大で野心的なメディアシリーズの50周年を迎えます。しかし、スタートレックはその誇り高い遺産に沿って50歳の誕生日を迎えますか?スタートレックの誕生日を祝う方法はたくさんあります。

更新:合法的な大統領候補は数百万人を怒らせ、美しい女性は苦しむ

更新:合法的な大統領候補は数百万人を怒らせ、美しい女性は苦しむ

(画像提供:ゲッティイメージズ)ドナルド・トランプは、アメリカ合衆国大統領の立候補者となる比類のない外交的洞察力を示し、何百万人もの人々を怒らせ、彼の時代遅れの客体化に対する評価の主要な情報源を失いました。彼が立候補を発表し終える前にパレード。トランプ氏は演説の中で、この国で最も高い役職に選出された場合、米国との南の国境に壁を建設すると述べた一連の声明を発表した。

インターネット上で最も愚かな親ロシアのデマ

インターネット上で最も愚かな親ロシアのデマ

David L. Sternは、ウクライナのキエフを拠点とするフリーランスのライターです。

ディズニーフリークは今、独自の出会い系サイトを持っています

ディズニーフリークは今、独自の出会い系サイトを持っています

オンラインデートに関しては、船長、ベーコン愛好家、ポットヘッド向けに作られたサイトなど、長年にわたって選択できるニッチなサイトがたくさんあります。今、ディズニーファンは彼ら自身のマッチメイキングサイトを通して愛を見つけることができます。

米国のフィギュア スケートは、チーム イベントでの最終決定の欠如に「苛立ち」、公正な裁定を求める

米国のフィギュア スケートは、チーム イベントでの最終決定の欠如に「苛立ち」、公正な裁定を求める

ロシアのフィギュアスケーター、カミラ・バリエバが関与したドーピング事件が整理されているため、チームは2022年北京冬季オリンピックで獲得したメダルを待っています。

Amazonの買い物客は、わずか10ドルのシルクの枕カバーのおかげで、「甘やかされた赤ちゃんのように」眠れると言っています

Amazonの買い物客は、わずか10ドルのシルクの枕カバーのおかげで、「甘やかされた赤ちゃんのように」眠れると言っています

何千人ものAmazonの買い物客がMulberry Silk Pillowcaseを推奨しており、現在販売中. シルクの枕カバーにはいくつかの色があり、髪を柔らかく肌を透明に保ちます。Amazonで最大46%オフになっている間にシルクの枕カバーを購入してください

パデュー大学の教授が覚醒剤を扱った疑いで逮捕され、女性に性的好意を抱かせる

パデュー大学の教授が覚醒剤を扱った疑いで逮捕され、女性に性的好意を抱かせる

ラファイエット警察署は、「不審な男性が女性に近づいた」という複数の苦情を受けて、12 月にパデュー大学の教授の捜査を開始しました。

コンセプト ドリフト: AI にとって世界の変化は速すぎる

コンセプト ドリフト: AI にとって世界の変化は速すぎる

私たちの周りの世界と同じように、言語は常に変化しています。以前の時代では、言語の変化は数年または数十年にわたって発生していましたが、現在では数日または数時間で変化する可能性があります。

SF攻撃で91歳のアジア人女性が殴られ、コンクリートに叩きつけられた

犯罪擁護派のオークランドが暴力犯罪者のロミオ・ロレンゾ・パーハムを釈放

SF攻撃で91歳のアジア人女性が殴られ、コンクリートに叩きつけられた

認知症を患っている 91 歳のアジア人女性が最近、47 番街のアウター サンセット地区でロメオ ロレンゾ パーハムに襲われました。伝えられるところによると、被害者はサンフランシスコの通りを歩いていたところ、容疑者に近づき、攻撃を受け、暴行を受けました。

ℝ

“And a river went out of Eden to water the garden, and from thence it was parted and became into four heads” Genesis 2:10. ? The heart is located in the middle of the thoracic cavity, pointing eastward.

メリック・ガーランドはアメリカに失敗しましたか?

バイデン大統領の任期の半分以上です。メリック・ガーランドは何を待っていますか?

メリック・ガーランドはアメリカに失敗しましたか?

人々にチャンスを与えることは、人生で少し遅すぎると私は信じています。寛大に。

Language