テンプレートメタ疑似乱数生成器 (雑)

#概略

C++ で `std::array<int, N>` の `N` に対して randomized test をやりたい、というめんどくさい欲求を抱いてしまったので、[この論文](http://www.researchgate.net/profile/Zalan_Szgyi/publication/259005783_Random_number_generator_for_C_template_metaprograms/links/00b49529b48272c5a6000000.pdf) を ~~丸パｋ~~さんこうに実装してみました[^1]。

[^1]: しかしこれ、SPLST'13 とかいう学会で発表実績があるらしいのに、DBLP にもひっかからないし Google Scholor の Bibtex にも情報量ゼロなのはなんなんだ。

#コード

自分は C++ のテンプレートはあまり詳しくないため、オボロゲに理解はできるけど、突っ込んだ説明は無理ゲーなので、解説は元論文をあたるか、お近くのテンプレートメタプロ魔王に聞いてみてください。丸投げメソッド。

```cpp
// tempra.hpp
#pragma once

#include <cstdint>
#include <climits>

template<uint32_t x, uint32_t y, uint32_t z, uint32_t w>
struct meta_xor128 {
    static const uint32_t x_ = x;
    static const uint32_t y_ = y;
    static const uint32_t z_ = z;
    static const uint32_t w_ = w;
    static const uint32_t value = w;
};

template<typename E>
struct eval {
    typedef E type;
};

template<typename E>
struct init {
    typedef typename eval<E>::type type;
    static const uint32_t value = type::value;
};
template<uint32_t x, uint32_t y, uint32_t z, uint32_t w>
struct init<meta_xor128<x,y,z,w>> {
    typedef typename eval<meta_xor128<x,y,z,w>>::type type;
    static const uint32_t value = type::value;
};

template<uint32_t x, uint32_t y, uint32_t z, uint32_t w>
struct eval<meta_xor128<x,y,z,w>> {
    #define t (x ^ (x << 11 ))
    static const uint32_t value = (w ^ (w>>19)) ^ (t ^ (t >> 8));
    typedef meta_xor128<y, z, w, (w ^ (w>>19)) ^ (t ^ (t >> 8))> type;
    #undef t
};

template<typename Engine>
struct Random {
    typedef typename init<Engine>::type type;
    static const decltype(type::value) value = type::value;
};

template <typename R>
struct Next {
    typedef typename eval<R>::type type;
    static const decltype(type::value) value = type::value;
};


constexpr char inits[] = __TIME__;
constexpr uint32_t DEFAULT_SEED = 
(inits[0]-'0')*100000+(inits[1]-'0')*10000 +
(inits[3]-'0')*1000+(inits[4]-'0')*100+
(inits[6]-'0')*10+inits[7]-'0';

typedef typename Random<meta_xor128<DEFAULT_SEED, DEFAULT_SEED+13, DEFAULT_SEED+34, DEFAULT_SEED+89>>::type META_PRNG;
```

##使用例

```cpp
// main.cpp
#include <array>
#include <iostream>
#include "tempra.hpp"

template<unsigned n, typename R>
struct print_randoms {
    static void print() {
        typedef typename Next<R>::type RND;
        std::cout << RND::value << std::endl;
        print_randoms<n-1, RND>::print();
    };
};

template<typename R>
struct print_randoms<0, R> {
    static void print() {
        std::cout << Next<R>::value << std::endl;
    };
};

template<unsigned n, typename R>
struct make_random_arity_array {
    static void print() {
        typedef typename Next<R>::type RND;
        std::array<int, RND::value % 65536> a;
        std::cout << "a is std::array<int, " << a.size() << ">" << std::endl;
        make_random_arity_array<n-1, RND>::print();
    };
};

template<typename R>
struct make_random_arity_array<0, R> {
    static void print() {
        typedef typename Next<R>::type RND;
        std::array<int, RND::value % 65536> a;
        std::cout << "a is std::array<int, " << a.size() << ">" << std::endl;
    };
};

int main(int ac, char** av) {
    print_randoms<10, META_PRNG>::print();
    make_random_arity_array<10, META_PRNG>::print();
    return 0;
}
```

```bash
$ gcc -std=c++11 main.cpp -lstdc++ -o tempra-test
$ ./tempra-test
172628
374345336
219481
2355161479
2573593181
265295047
352538101
2661593603
673551496
2816265063
2831111820
a is std::array<int, 41556>
a is std::array<int, 3704>
a is std::array<int, 22873>
a is std::array<int, 59783>
a is std::array<int, 59997>
a is std::array<int, 5319>
a is std::array<int, 19957>
a is std::array<int, 45571>
a is std::array<int, 38024>
a is std::array<int, 52071>
a is std::array<int, 22156>
```

#注意

疑似乱数列は**コンパイル時に定まっている**ので (ほぼ by definition)、同じバイナリを何回も実行して「ちっともランダムじゃないじゃないか！」とか怒らないようにしましょう。