this はつけるべきか

C++ (や Java その他の言語)において, メンバ変数や関数のアクセスに this->をつけるべきか否か, という疑問があり, 調べてみた.

this をつけるべきかどうかについてはコーディング規約や好みの問題で議論されている(た). が, 何か決定的な違いがあったような気がしてもやもやしていた.

次の点は, 個人やプロジェクトの嗜好ではなく技術的にはっきりと意識すべき違いをもたらす.

#include <iostream>
struct X { void hoge () { std::cout << "hoge" << std::endl; } };

template <typename T>
struct A { void foo () { T x; x.hoge(); } };

template <typename T>
struct B : public A<T> { void bar () { foo(); } }; /* ※1 */

int main () {
  B<X> b;
  b.bar();
  return 0;
}
x.cpp: In member function ‘void B<T>::bar()’:
x.cpp:8: error: there are no arguments to ‘foo’ that depend on a \
template parameter, so a declaration of ‘foo’ must be available
x.cpp:8: error: (if you use ‘-fpermissive’, G++ will accept your \
code, but allowing the use of an undeclared name is deprecated)

B::foo() は A::foo() を継承しているはずなのに, コンパイラは foo の定義が見つからないといっている.

これを解決する手段は:

  • foo() の呼び出しを書き換えて this->foo() にする
  • foo() の呼び出しを書き換えて A<X>::foo() にする
  • using A<X>::foo; 宣言 (using-declaration) を追加する.

また, foo がテンプレート引数の typename T に依存していれば, thisをつけなくても名前を見つけてくれるらしい. フ..フクザツな!

これは, テンプレート化された基底クラス内の名前へのアクセスするために知っておくべき方法らしい. 実は, 以前読んだ Effective C++ に書いてあった (やっぱり手元に置いてたまに見返さないといけないなぁ).

有名な本に載っているくらいだから, 有名な事実なんだろうけど, 検索でひっかかりにくかったので, こんなエントリを書いてみました, と.

あと, 仮想関数とか継承関係の問題がほかにもあったような気がするのだけど思い出せない. 気のせいかもしれない.

《参考》

追記

cppll_novice にて, どんぴしゃなスレッドが見つかりました...

ADL (argument dependent lookup) とか two-phase name lookup が関係するらしい, と. ふむふむ.