式の型で変数を宣言する

C#3.0では、varキーワードで変数を宣言すると初期化の式から適当にその変数の型を推論してくれる。それをC++でもやってみようと。本格的なヤツはBoostにあるが、それの原理みたいなもの。

#include <iostream>

template<typename T>
struct type_id;

template<std::size_t id>
struct id_to_size {
    char dummy[id];
};

template<std::size_t id>
struct id_to_type;

template<typename T>
id_to_size<type_id<T>::value> test(T);

#define TYPEOF(expr) id_to_type<sizeof(test(expr))>::type

#define REGIST_TYPE(type_, id)     \
    template<>                     \
    struct type_id<type_> {        \
        enum {                     \
            value = id             \
        };                         \
    };                             \
                                   \
    template<>                     \
    struct id_to_type<id> {        \
        typedef type_ type;        \
    };

REGIST_TYPE(char, 1)
REGIST_TYPE(unsigned char, 2)
REGIST_TYPE(short, 3)
REGIST_TYPE(unsigned short, 4)
REGIST_TYPE(int, 5)
REGIST_TYPE(unsigned int, 6)
REGIST_TYPE(long, 7)
REGIST_TYPE(unsigned long, 8)
REGIST_TYPE(float, 9)
REGIST_TYPE(double, 10)

struct Foo {
    void print() {
        std::cout << "foo" << std::endl;
    }
};

struct Bar {
};

Foo operator+(int, Bar);

REGIST_TYPE(Foo, 11)

int main() {
    using std::cout;
    using std::endl;

    int i;
    double d;

    TYPEOF(i + d) c = 1.5;
    TYPEOF(1 + Bar()) foo = Foo();

    cout << c << endl;
    foo.print();

    return 0;
}

かなりいい加減な思い付きだったがすんなりとできた。boost::typeofの実装はあんまり見てないから分からんが、上と同じように、

  1. 式をダミーの関数に渡して型を取る
  2. その型の色んな情報を整数にする
  3. サイズにする
  4. sizeofでまた整数にする
  5. テンプレートに放りこんで元の型に復元

という手順で式の型を取り出している。ただ、型の色んな情報をsizeofで取り出しているので、Tを登録すればT*とかを登録する必要はない。すごい。確かにすごいのだが…。


えんいー