質問: value; } public: SomeType member_; }; // 子クラス template struct Derived : Base, SomeType> { void implementation() { std::cout << member_ << std::endl; } }; int main(int argc, char *argv[]) { Derived obj; obj.set_value(1); obj.interface(); } ``` このコードは VC++ では問題なく通り、実行すると `1` とメンバ変数 `member_` の値が出力されます。 しかし、gcc でビルドすると以下のコンパイルエラーが発生します。 ``` error: ‘member_’ was not declared in this scope std::cout << member_ << std::endl; ^ ``` this ポインタから参照するように修正すると、gcc でもコンパイルが通ります。 ``` - std::cout << member_ << std::endl; + std::cout << this->member_ << std::endl; ``` --- 自分の理解では、public で継承しているので、親クラスでアクセス修飾子が protected である member_ には、子クラスからもアクセスできるはずとの認識ですが、なぜ変数が定義されていないとエラーになってしまうのでしょうか。 聞きたいこと ------ * gcc でコンパイルエラーとなる理由 * C++ の仕様としては「コンパイルが通る」または「コンパイルエラーとなる」のどちらが正しいのか すみませんが、よろしくおねがいします。
回答: こんにちは。 それは、標準規格通りの動作です。 テンプレート引数が確定しないと(実体化しないと)確定しないものは、最初の名前解決の時には無視されるようです。そして、それらは次のフェーズである実体化処理時に名前解決されます。 `Base, SomeType>`は、SomeTypeが決まらないと決まりません。なので、そのメンバ変数のmember_も確定しません。(仮にint型だったとしても同様です。Baseが特殊化されていて、特殊化の方にはmember_がないことも許されますから。) しかし、使う側は member_ で呼び出しているだけで特に限定する修飾がなく、テンプレート引数に依存していません。結果、これは最初の名前解決の際にマッチングされます。 つまり、最初の名前解決時、使う側は「あるもの」なので名前解決しようとします。しかし、その時、規定クラスの member_ はテンプレート引数に依存しているので無視され、名前解決エラーになります。 使う際に「this->member_」とすると、これはthisのメンバという限定修飾をしています。thisはテンプレート引数に依存しているので、最初の名前解決では同じく無視され、実体化時に名前解決されるので両者めでたくマッチングされます。 このような挙動は、Two phase name lookupと呼ばれるそうです。下記に詳しい記述がありました。 テンプレートクラスの内部クラスの継承における基底クラスのメンバ変数検索