Qt4.2.2 を VS2005+SP1(vc8) で使う

meta-creation_date: 2006-12-17T05:30:45+09:00
meta-entiry_id: qt4_msvc8_sp1_problem
meta-author: t.ashula
meta-tags: Programming,Qt4,MSVC,C++,SP1

MSDNへの登録が必要のようだがhttp://support.microsoft.com/kb/930198 にてHotfixが入手できる模様.

いつの間にか,前述のページが無味乾燥としたものになってるので,愚繰ってたどり着いた 主に non Japanese のために Qt4 with Visual Studio - qtnode にリンクしておく

VisualStudio2005 の SP1 が出たので,さっくり導入.

400MiB を超えてるせいか,1時間くらいかかってやっとインストール完了.

使った範囲内で問題は出てない—というより,改善点がよくわからない—のだけど,ひとつだけ大問題が発生.

Qt4 のコンパイルに失敗してしまうのだ.


そもそも,MSVCはQt4の Windows/GPL 版の対象外なので,使えなくてもしょうがないっちゃしょうがないんだけども.Q../Freeのパッチを当てると,VisualStudio2005 + PlatformSDK でもコンパイルが可能.

ところが,VS2005にSP1を当てると,QMultiMapQMultiHashがコンパイル出来無くなった.

調べてみると,QT-interest のメーリングリストにQt-interest Archive - VS2005 SP1 Final Breaks Qtってなスレッドを発見.そこからさらにMSDN のforumのVisual Studio 2005 Service Pack 1 Beta - error C2244に行き着いた.

どうやら,Qt に限らず,VC8 のテンプレート処理が何かまずいらしい.つまり,template class A の中で typedefした型を, BというAを継承したテンプレートクラスの中の関数が返そうとするとコンパイルできないので.コンパイルするには class B の中で改めて typedef してそっちを使うようにとVisual Studio 2005 Service Pack 1 release notesRecent versions of the Qt library source give errors on compilation:に書いてある.

コードのほうがわかりやすいので丸々引用すると.

  template <class T>
  class A
  {
    public:
      typedef int N_A;
  };
 
  template <class T>;
  class B : public A<T>
  {
    public:
      typename A<;T>::N_A test();
  };
 
  template <class T>
  typename A<T>::N_A B<T>::test()    /* 1 */
  { 
    return 0;
  }

とすると/* 1 */ のところでコンパイルエラーになるので

  template <class T>
  class A
  {
    public:
      typedef int N_A;
  };
 
  template <class T>
  class B : public A<T>
  {
    public:
      typedef A<T>::N_A N_B;  // typedef definition
      typename N_B test(); // use of the typedef in the return type
  };
 
  template <class T>
  typename B<T>::N_B B<T>::test()    // use of the typedef in the return type
  { 
    return 0;
  }

という風にしなさいよということのようだ.

それならばと,Qtの問題の箇所の QMultiMapとQMultiHash を確認してみる

具体的には QMultiMap は,QTDIR\src\corelib\tools\qmap.h

  906: template <class Key, class T> 
  907: Q_INLINE_TEMPLATE Q_TYPENAME QMap<Key, T>::iterator 
        QMultiMap<Key, T>::replace(const Key &amp;akey, const T &amp;avalue)
  908: { return QMap<Key, T>::insert(akey, avalue); }
  909: 
  910: template <class Key, class T>
  911: Q_INLINE_TEMPLATE Q_TYPENAME QMap<Key, T>::iterator 
        QMultiMap<Key, T>::insert(const Key &amp;akey, const T &amp;avalue)
  912: { return QMap<Key, T>::insertMulti(akey, avalue); }

QMultiHash は,QTDIR\src\corelib\tools\qmap.h

  864: template <class Key, class T> 
  865: Q_INLINE_TEMPLATE Q_TYPENAME QHash<Key, T>::iterator 
       QMultiHash<Key, T>::replace(const Key &amp;akey, const T &amp;avalue)
  866: { return QHash<Key, T>::insert(akey, avalue); }
  867: 
  868: template <class Key, class T>
  869: Q_INLINE_TEMPLATE Q_TYPENAME QHash<Key, T>::iterator 
        QMultiHash<Key, T>::insert(const Key &amp;akey, const T &amp;avalue)
  870: { return QHash<Key, T>::insertMulti(akey, avalue); }

のあたり.これを,リリースノートの状況に照らし合わせると

class Aclass QMap/QHash
class Bclass QMultiMap/QMultiHash
N_Aiterator
test()replace()/insert()

となるので,QMultiMap の修正は,typedefQMultiMap::QMapItr 型を追加.inser(),replace()の返り値を QMultiMap::QMapItr 型にすると言うことになる.

  class QMultiMap : public QMap<Key, T>
  {
    public:
      typedef QMap<Key, T>::iterator QMapItr;  // rename
      inline typename QMapItr insert( const Key &amp;key, const T &amp;value );
  }
  template <class Key, class T> 
    Q_INLINE_TEMPLATE Q_TYPENAME QMultiMap<class Key, class T>::QMapItr 
    QMultiMap<class Key, class T>::insert(const Key &akey, const T &avalue)
    { return QMap<Key, T>::insert(akey, avalue); }

それで,QMultiMap::replace, QMultiHash::insert, QMultiHash::replace も同様にしてみたのをqt4-multi-map-hash-msvc8-sp1.diff においておくのですが,patch の使い方が良くわからないので,使いたい人は,diffファイルの中身を見て適当に解釈してどうぞ.