メタ関数で型を変換する

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


テンプレートメタプログラミング - (void*)Pないとの続きです。

今度は型を変換するメタ関数の登場です。

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

template<class T>
struct types {
    typedef T type;
};

int main () {
    types<int>::type i;
    return 0;
}

このコードは、インスタンス化されると

int main () {
    int i;
    return 0;
}

に置き換わります。例によって例の如く、これだけじゃだからどうした?っていう話ですね。そこで型の変換を行ってみます。

ある型を参照型に変換する処理を考えてみます。

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

template<class T>
struct types {
    // 参照型に変換
    typedef T& type;
};

int main () {
    int i = 100;
    types<int>::type j = i;
    
    i = 300;
    
    cout << j << endl;
    return 0;
}
$ main
300

となります。

ただしこのままだと、もしtypes<>にint&型を渡した場合int&&に変換されてしまい、コンパイルエラーになります。

main.cpp
main.cpp(6) : error C2529: 'type' : 参照への参照は無効です。
        main.cpp(16) : コンパイルされたクラスの テンプレート のインスタンス化 'types<T>' の参照を確認してください
        with
        [
            T=int &
        ]

なので特殊化を利用し、参照型が渡された場合はそのまま返すようにします。

template<class T>
struct types {
    typedef T& type;
};

// 参照型が渡された場合だけ特殊化。そのまま返す
template<class T>
struct types<T&> {
    typedef T& type;
};

これで完成です。

さて今度はある型からconst型を外す処理を考えてみます。

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

// const付いてない場合はそのまま
template<class T>
struct types {
    typedef T type;
};

// const付いてる場合だけ特殊化。外して返す
template<class T>
struct types<const T> {
    typedef T type;
};

int main () {
    types<const int>::type i = 100;
    
    // 書き換え可能。エラーにならない。
    i = 300;
    
    return 0;
}

基本的には同じような感じですね。

型変換のメタ関数を色々用意しておけば、各所でtypedefせずに済むのでかなり便利かもしれません。