range-based for

C++0x の規格制定で、範囲 for 構文をどうするかが議論になっているようです。


本の虫: range-based forに対する意見求む
range-based for の変更案 - Togetter


僕としては、案4の「メンバ関数を呼び出す」が妥当かと思います。
というのも、 ADL というのは非常にタチが悪く、

#include <iostream>
 
namespace A
{
  template<class T>
  void f( T& x ){ std::cout << "A::f\n"; }
 
  class Base {};
 
}
 
namespace B
{
  class Derived : A::Base {};
 
  void f( Derived const& x ){ std::cout << "B::f\n"; }
 
}
 
int main()
{
  B::Derived x;
  f(x);
}

上記のようなコードがあった場合、殆どの人は正しい動作(http://ideone.com/t3GPF)を予測できないからです。


traits ベースの実装は、標準ライブラリによるサポートが必須である上、
あまり C++ に慣れていない人に、詳細な仕組みを説明するのが面倒です。
しかも public 継承が絡んだ場合、明示的に特殊化しない限り、デフォルトに戻ってしまいます:

#include <iostream>
 
template<class T>
struct some_traits
{
  static void invoke( T const& ){ std::cout << "default\n"; }
};
 
template<class T>
void f( T const& x )
{
  some_traits<T>::invoke(x);
}
 
struct Base {};
 
template<>
struct some_traits<Base>
{
  static void invoke( Base const& ){ std::cout << "specialized\n"; }
};
 
struct Derived : Base {};
 
int main()
{
  Base x;
  f(x); // specialized version
 
  Derived y;
  f(y); // default version
 
}

http://ideone.com/KeSZt
というわけで、初心者には優しくない。


メンバ関数を使えば、そういう問題は一切なくなります。
何より、分かりやすい。これが一番のメリットでしょう。
問題は配列に対して range-based for を使いたい場合で、
その場合は規格上で特別扱いするか、あるいは配列専用のアダプタを作る必要がありますが、

実は現行のドラフトでも、 range-based for に対して配列が渡された場合は、特別扱いすることになっています。
というわけで、その記述をそのまま引き継げばいいだけで、特に問題にはならないでしょう。


何より、メンバ関数を使えば、特に規格を大きく変更すること無く、ADLを排除できます。
これは大きく、例えば traits を使った場合、 のような専用のヘッダを用意する必要がある筈であり、
その記述をする分だけ、規格に大きな変更が必要になるでしょう。
僕としては、そういうのは嫌です。何故なら、とにかく早く C++0x は確定して欲しいから。


というわけで、僕としては、案4の「メンバ関数によって begin, end を呼び出す」のがいいかな、と思いました。