2006-01-18-01-型伝播の悩み事 - project-enigma

2006-01-18-01-型伝播の悩み事

>> Site top >> weblog >> 月別アーカイブ >> 2006年01月のlog >> 2006-01-18-01-型伝播の悩み事

最終更新日付:2014/01/02 00:00:00


型伝播の悩み事

2006 年 01 月 18 日

...というタイトルでエントリを書いたのだが、プログラミングをやらない人には面白くもなんともない内容になってしまった。そのため、内容の大半は「続きを読む」の向こう側に置く事にする。結論としては、Microsoft Visual C++ 6.0 は標準 C++ への準拠という点からは少々古いんだね...ということである。まぁ8年も前のコンパイラだし、この10年でC++は大きく変わったから無理もないのだけれど。

C++ のテンプレートあたりに興味のある方は読んでいただけると幸いである。もちろんそれ以外の人も歓迎するが、あくびがでないことを祈る。なお、別に目新しいことを書くわけではない。それでは、

C++ のクラステンプレートでは、テンプレート引数を typedef することで、後から型情報を拾うことができる。たとえば、以下のようなクラスがあるとしよう。

template <typename T>
class Foo {
public:
    typedef T ParamT;
};

こうなっていれば、Foo<int>::ParamT は int 型である。

次に、テンプレートの特殊化について。あるクラステンプレート、およびそのクラステンプレートのポインタ型に対する特殊化を用意したとする。以下のように。

template <typename T>
class Baz {
    // 定義A
};

template <typename T>
class Baz<T*> {
    // 定義B
};

こうなっていると、Baz<int> であれば定義Aが使用され、Baz<int*> であれば 定義Bが使用される。結論からいうと、この特殊化が Microsoft Visual C++ 6.0 ではコンパイルできないのだ。

この機能は、テンプレートを駆使したプログラミングでは有用なテクニックで、STL などでも使用されている(と記憶している)。例として、ポインタの一般化としての反復子をパラメータとするテンプレートを考えよう。そのテンプレートでは反復子の型をIteratorT、その反復子が指す値の型を ValueT として typedef したい。反復子自身がValueT を提供するとして、それは以下のように書ける。

template <typename ITR>
class Qux {
public:
    typedef ITR                   IteratorT;
    typedef typename ITR::ValueT  ValueT;
};

しかし、このテンプレートにはポインタ型を渡せない。ポインタは ValueT を提供しないからだ。そこで、以下のような特殊化を用意する。

template <typename VAL>
class Qux<VAL*> {
public:
    typedef VAL* IteratorT;
    typedef VAL  ValueT;
};

こうすれば、Qux<iterator> でも Qux<object*> でも対応できる...少なくとも標準 C++ に準拠していればこのコードはコンパイル可能だ。以下のような感じで。

#include <iostream>
 
template <typename ITR>
class Qux {
public:
    typedef ITR                  IteratorT;
    typedef typename ITR::ValueT ValueT;
};
 
 
template <typename VAL>
class Qux<VAL*> {
public:
    typedef VAL* IteratorT;
    typedef VAL  ValueT;
};
 
class Dummy {
public:
    typedef int ValueT;
};
 
int main( void ) {
 
    typedef Qux<Dummy>    Qux1;
    typedef Qux<char*>    Qux2;
 
    std::cout << "size of Qux<Dummy>::ValueT is " << sizeof( Qux1::ValueT ) << std::endl;
    std::cout << "size of Qux<char*>::ValueT is " << sizeof( Qux2::ValueT ) << std::endl;
 
    return 0;
}

...一応、Windows 上で動作する gcc(多分 2.95 かな)ではコンパイルできたし、結果も正しかった。しかし、 VC++6.0 ではコンパイルできない。もちろん、この機能が使えないとしても代替策はある。しかし、それをやるとコードが煩雑になるのでやりたくないのだ...ところで、いくつかの理由でいまだに 6.0 を使用しているわけだが、このあたりの「重箱の隅っこ」は最近のリリースでは標準に準拠するようになったのだろうか? もちろん、そうだとしても安易に乗り換えるのも怖い。世の中ではまだ VisualStudio 6.0 が現役で使用されていたりもするからだ。最新のコンパイラでなければ通りません、というのも別の意味で困る...はてさて。

 

コメント

このページにコメントする

 

このページのタグ

Page tag : 開発

 

 


Copyright(C) 2005-2017 project-enigma.
Generated by CL-PREFAB.