Qt foreachの注意点 その1

c++11で範囲for文(range-based for)が追加されたことで、c++でも以下のようにコンテナの内部のすべての要素を簡単に捜査できるようになりました。

std:vector<int> vec;
for( const int value : vec )
{
  std::cout << value << std::endl;
}

Qtではc++の言語機能としてこの機能が追加される以前からQt独自の拡張としてforeach機能を提供しており、以下のようにコンテナの要素を簡単に捜査することができました。

QVector<int> vec;
foreach( const int value, vec )
{
  qDebug() << value;
}

このようにc++11が使えない環境では大変便利なforeach機能ですが1つ注意点があり、
以下の例のようにコンテナの内部要素の型にカンマが入っているとコンパイルエラーとなります。

QVector< QPair<int,int> > vec;
foreach( const QPair<int,int> &value, vec )
{
  qDebug() << value.first << value.second;
}

clangだとこのようなエラー内容

error: too many arguments provided to function-like macro invocation

これはQtのforeach機能がマクロで実装されているため、型のカンマが引数の区切りとして以下のように解釈されてしまうことでこのようなエラーが発生します。

foreach( (const QPair<int), (int> &value), (vec) )

このエラーはコンテナの内部要素の型をtypedefしてやることで回避出来ます。

typedef QPair<int,int> Pair_t;
QVector<Pair_t> vec;
foreach( const Pair_t value, vec )
{
  qDebug() << value.first << value.second;
}


知らないときにエラーになって少しはまったことがあるのでメモ。


ちなみにboostのBOOST_FOREACHでも同じ理由から同様のエラーが起きるようです。

参考
Container Classes | Documentation | Qt Project
C++でforeachみたいなことができるBoost.Foreach - ぬいぐるみライフ(仮)