型特性メタ関数

C++テンプレートテクニック 5-3


特殊化を利用して型をチェックするメタ関数を作る

#include <iostream>
using std::cout; using std::endl;

template<class T>
struct is_pointer {
    static const bool value = false;
};
template<class T>
struct is_pointer< T* > {
    static const bool value = true;
};

int main () {
    
    cout << is_pointer<int>::value << endl;
    cout << is_pointer<int*>::value << endl;
    
    return 0;
}
$ main
0
1

ここまでOK。

次は、ある型が特定の型を持っているかどうかをチェックするメタ関数を作るという話。

ここがかなりややこしかった。下記コードをひとつひとつ理解しながら読んでいく。

#include <iostream>
#include <vector>
using std::cout; using std::endl;

template<class T>
class has_iterator {
    typedef char yes;
    typedef struct { char a[2]; } no;
    
    template<class C>
    static yes test(typename C::iterator*);
    
    template<class C>
    static no test(...);
public:
    static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};

int main () {
    cout << has_iterator<std::vector<int>>::value << endl;
    cout << has_iterator<int>::value << endl;
    return 0;
}

まずyesとnoですが、サイズを別々にするためにcharとchar[2]型にして宣言してます。

次にtestという関数を宣言します。SFINAEにより、yesを戻り値とする関数か、noを戻り値とする関数かにわかれます。

そしてtest(0)という呼び出しをしています。これは本来ならtest関数の引数に0を渡した関数呼び出しになるはずなんですが、sizeofの特殊な仕様により戻り値の型のサイズが返り、そのサイズがyes型と同じサイズかどうかをチェックすれば、晴れて完成となります。

凄いですねー。

他にもある型がクラスかどうかを判断するis_classの実装例も載っていました。色々勉強になります。