恋人と一緒に聴けるヘヴィメタル10選
- バトル枠
-
- Turisas - Battle Metal (Battle Metal 収録)
聞け! 我が戦士たちよ! 全世界の果てから来た戦士達よ!
我らの軍に加わろう 軍を組織するのだ
四つの風が我らを導き チュリサスの心が我らを先導する!
-
- Rhapsody - Warrior Of Ice (Legendary Tales 収録)
- ニンジャ枠
-
- Europe - Ninja (The final countdown 収録)
-
- DragonForce - Strike of the Ninja (Ultra Beatdown 収録)
我々には夜でさえ燃える火のように明るい
戦士の生きるべき場所、死すべき場所は何処なり
どこまでも側に仕えよう ニンジャスピリットが夜を駆けるだろう
今宵 ニンジャよ永遠なれ!
ハーマンはイケメン
- アニキ枠
-
- Manowar - Loki God of Fire (Gods of War 収録)
-
- Rammstein - Mann gegen Mann (Rosenrot 収録)
- ハゲ枠
-
- Hibria - The Anger Inside (The Skull Collectors 収録)
-
- Iron Savior - Heavy Metal Never Dies (The Landing 収録)
-
- Primal Fear - Fighting The Darkness
-
- Judas Priest - Jawbreaker (Defenders Of The Faith 収録)
文句無しに人に薦められるライトノベル9選
本棚を少し整理した折りにふと思いついたので、個人的ライトノベル傑作選をリストにしました。
どれも完成度と面白さで文句無しなので、友達に推薦しても喜ばれること請け合いです。
ついでに内容を一行に纏めたので、未読の人は参考に、この機会に手に取ってみてはどうでしょう。
- タフガイ枠
-
- 東出祐一郎 『ケモノガリ』
だが全世界のあらゆる日本人の中で、おまえ一人だけはジャップだ。タイニー・タイニー・ファッキン・ジャップだ。
-
- 虚淵玄 『アイゼンフリューゲル』
- SF枠
ガリレオ・ガリレイ vs アーネスト・ホースト。
- 学園枠
-
- 江波光則 『パニッシュメント』
学園版ドストエフスキー。
-
- 田中ロミオ 『AURA 〜魔竜院光牙最後の闘い〜』
- レイプ枠
-
- 江波光則 『ペイルライダー』
クリント・イーストウッド扮する牧師が無法者ラフッド一味相手に無双する。
メタ関数の実装技法 - その2
前回(メタ関数の実装技法 - その1 - ボレロ村上 - ENiyGmaA Code)に続き、メタ関数の実装技法その2です。
関数の呼び分けと decltype を利用したメタ関数
たとえば、クラスメンバに型名 value_type を持つか判定するトレイトを考える。
-
- has_value_type
template<typename T, typename U = typename T::value_type> std::true_type value_type_tester(int); template<typename T> std::false_type value_type_tester(long); template<typename T> struct has_value_type : decltype(value_type_tester<T>(0)) {};
これは value_type_tester の呼出において、T::value_type が定義されている場合は上が呼び出され、そうでない場合は下が呼び出される。
その返値型を decltype で取ることによって(true_type | false_type)メンバの有無を判定する。
なお引数が int と long になっているのは、返値型のみが異なる関数を宣言することはできないからである。
またテンプレート引数を非型にすれば、非型メンバに対するトレイトを定義することもできる。
こうしたトレイトは、しばしば has_xxx と呼ばれるものである。
本の虫: C++11におけるモダンなhas_xxxの実装
優先順のある複数条件の特殊化によってメタ関数を書く
たとえば、ある条件を満たすときの動作、そうでないが別の条件を満たすときの動作、いずれの条件も満たさない場合の動作、
……といった具合に、if-else if のように動作をフォールバックさせたいときがある。
SFINAE でこれをやりたい場合は、以下のような方法がある。
enable_switch - 複数の重複しうるコンパイル時条件で、SFINAE によるオーバーロードを書くには - ボレロ村上 - ENiyGmaA Code
またメタ関数の実装においては、部分特殊化によって同じようなことをもっと簡単にやることもできる。
たとえば、以下のような3つのコンテナクラスがあったとする。
template<typename T> struct FuckinContainer1 { typedef T value_type; value_type* begin(); value_type* end(); }; template<typename T> struct FuckinContainer2 { typedef T* iterator; iterator begin(); iterator end(); }; template<typename T> struct FuckinContainer3 { typedef T const* const_iterator; const_iterator begin(); const_iterator end(); };
さて、これらのクラスは困ったことに、value_type や iterator といったメンバ型が統一的に用意されていない。
そもそも自作コンテナをどうこうすることから疑うべきだが、もしあなたのプロジェクトにこういう不統一をするプログラマがいたら即刻窓から投げ捨てるべきである。
しかしながら現実はそう単純ではない。
その糞コードを書いた人間はすでに死んでいて直す者がいないかもしれないし、そもそも手を入れることができないライブラリの中に糞コードが入っているかもしれない。
そのような既存の糞コードや、あるいはこれから生み出されるかもしれない糞コードにも、可能な限り対応できるコードを書かなければならない時もある。
ここでは、上記の糞コンテナクラスから、なんとかして全てから value_type を取り出すようなメタ関数を考える。
-
- container_value_type
/* has_xxx のバリエーション。実装は上記参照 */ template<typename T> struct has_value_type; template<typename T> struct has_iterator; template<typename T> struct has_const_iterator; template<typename C, bool HasValueType, bool HasIterator, bool HasConstIterator> struct container_value_type_impl {}; template<typename C, bool HasIterator, bool HasConstIterator> struct container_value_type_impl<C, true/*HasValueType*/, HasIterator, HasConstIterator> { typedef typename C::value_type type; }; template<typename C, bool HasConstIterator> struct container_value_type_impl<C, false/*HasValueType*/, true/*HasIterator*/, HasConstIterator> { typedef typename std::iterator_traits<typename C::iterator>::value_type type; }; template<typename C> struct container_value_type_impl<C, false/*HasValueType*/, false/*HasIterator*/, true/*HasConstIterator*/> { typedef typename std::iterator_traits<typename C::const_iterator>::value_type type; }; template<typename C> struct container_value_type : container_value_type_impl< C, has_value_type<C>::value, has_iterator<C>::value, has_const_iterator<C>::value > {};
見てのとおり、container_value_type_impl は三段階に部分特殊化されている。
インタフェースとなる container_value_type は、各々の has_xxx による判定結果を container_value_type_impl に転送する役目である。
このような手法は、なにも糞コードへの対応に限ったものではない。
クラスのコンセプトを決めるとき、
-
- 型 xxx が定義されていること
- 型 yyy が定義されていること [Optional] (定義されていない場合は xxx から推論される)
このような形にすることで、コンセプトが要求する最小要件を小さくすることができる。
そうしたコンセプトを基にした実装において、こうした手法が必要になることがある。
(たとえば std::allocator_traits など)
メタ関数の実装技法 - その1
そもそもメタ関数とは
(参照:More C++ Idioms/メタ関数(Metafunction) - Wikibooks)
一般に C++ でメタ関数とは、与えられたテンプレート引数から、結果として何か型やコンパイル時定数を返す(定義する)ようなクラステンプレートをいう。
代表的な例としては
ところで、Boost.MPL などでは(統一性のために)テンプレート引数が型名のみになるように設計されているが、
標準ライブラリでは(直観的な記述のために)真理値を指定するテンプレート引数をコンパイル時定数でとるなど、
一口にメタ関数と言ってもその厳密な範囲は設計方針によって多少の差異がある。
(もっとも、Boost.MPL ではメタ関数 xxx に対してコンパイル時定数をとるバージョンの xxx_c を用意していたりするが)
-
- boost::mpl::if_
namespace std { template<typename C, class T , class F> struct if_; }
-
- std::conditional
namespace std { template<bool C, class T, class F> struct conditional; }
メタ関数について概ね共通しているコンベンションは、
-
- 結果として型を返す場合は型名 type を定義する。
- 結果として値を返す場合はコンパイル時定数 value を定義する。
この2点だろう。
また std::iterator_traits のように、複数の型名を結果として定義するようなトレイトもメタ関数と呼ばれる場合があるが、
特定の用途ではなく汎用的に用いたい場合は上に挙げたコンベンションに従うべきだろう。
この記事では、さしあたってごく基本的なメタ関数の定義の仕方について書くものとする。
簡単な条件の組み合わせのメタ関数を書く
まずは
ここでは試しに「型が符号無し整数型であるか」判定するプレディケートを書く。
前提として、std::is_unsigned は算術型が符号無しであるか判定するが、これは浮動小数点型も含むため整数型に絞る必要がある。
-
- is_uint
template<typename T> struct is_uint // 整数型かつ符号無し : std::integral_constant<bool, std::is_integral<T>::value && std::is_unsigned<T>::value> {};
自分で value メンバを定義しても概ね同じことだが、継承を使っているのには理由がある。
なぜなら
という形で規格に定められており、自分でメタ関数を書く場合でもこれに合わせるべきだからである。
それによって value だけでなく type, value_type メンバも自動的に定義される。
(なお、std::true_type/false_type は std::integral_constant
簡単な特殊化によってメタ関数を書く
たとえば、型が特定のクラステンプレート X のインスタンスであるかを判定したいときがある。
-
- is_x_class
template<typename T> class X {}; template<typename T> struct is_x_class : std::false_type; template<typename T> struct is_x_class<X<T> > : std::true_type; template<typename T> struct is_x_class<T const> : is_x_class<T>; template<typename T> struct is_x_class<T volatile> : is_x_class<T>; template<typename T> struct is_x_class<T const volatile> : is_x_class<T>;
この場合は(部分)特殊化によってプレディケートを書くことができる。
デフォルトでは false であり、部分特殊化が X
またこのような場合、X
そのようなときは、cv修飾された型に対しては非修飾型についての結果を返すように丸投げすればうまくいく。
こうすることで、後に別のクラス X2 を条件に追加したくなった場合でも、X2 の部分特殊化だけを追加すればよい。
enable_if によってメタ関数を書く
整数型のサイズを返すメタ関数を考える。
-
- integral_size
template<typename T, typename = void> struct integral_size; template<typename T> struct integral_size<T, typename std::enable_if<std::is_integral<T>::value>::type> : std::integral_constant<std::size_t, sizeof(T)> {};
enable_if については、今更説明の必要もないだろう。
このような宣言をする場合、ユーザに enable_if で特殊化するための口を公開しているのと同じである。
別の場所で異なる型について integral_size を使えるにしようとした場合、ユーザは通常の特殊化によらない自由な条件式を記述できる。
とはいえ、それは良し悪しであって、こうした方法が本当に必要になるケースというのは実際のところあまりお目に掛かったことがない。
コンパイル時数列生成 generate/unfold/recurrence
Sprout C++ Library
Github https://github.com/bolero-MURAKAMI/Sprout
ご存じのように Sprout には constexpr アルゴリズムがある。
ここでは、そのうち generate と unfold, および recurrence について解説する。
というのも、最近これらについてかなりの破壊的変更が入ったからである。
STL の generate について
さて、STL のアルゴリズムに std::generate というのがある。
namespace std { template<typename ForwardIterator, typename Generator> void generate(ForwardIterator first, ForwardIterator last, Generator gen); }
これは、関数オブジェクト gen を次々と呼び出してその返り値をイテレータに格納してゆくものである。
たとえば、このようにして数列などを生成することができる。
-
- std::generate でフィボナッチ数列を生成
#include <algorithm> #include <array> #include <iostream> template<typename T> struct fib { T a, b; constexpr fib() : a(-1), b(1) {} constexpr fib(T a, T b) : a(a), b(b) {} T operator()() { std::swap(a, b); return b += a; } }; int main() { std::array<int, 30> arr{}; std::generate(arr.begin(), arr.end(), fib<int>()); for (int e : arr) { std::cout << e << ' '; } std::cout << std::endl; }
-
- 出力
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229
-
- std::generate で [1..6] の整数一様分布の乱数列を生成
#include <ctime> #include <algorithm> #include <random> #include <functional> #include <array> #include <iostream> template<typename Rng, typename Dst> struct rng { Rng& r; Dst& d; constexpr rng(Rng& r, Dst& d) : r(r), d(d) {} auto operator()() -> decltype(d(r)) { return d(r); } }; template<typename Rng, typename Dst> constexpr rng<Rng, Dst> make_rng(Rng& r, Dst& d) { return {r, d}; } int main() { std::array<int, 30> arr{}; std::default_random_engine rng(std::time(0)); std::uniform_int_distribution<int> dst(1, 6); std::generate(arr.begin(), arr.end(), make_rng(rng, dst)); for (int e : arr) { std::cout << e << ' '; } std::cout << std::endl; }
-
- 出力
6 5 1 2 4 2 4 5 4 2 1 3 1 3 4 2 1 1 4 6 4 2 5 2 1 6 3 2 3 5
見て分かるように、前の項の計算結果を利用したり、状態を更新したりする場合は、関数オブジェクト gen の呼出が副作用を持たねばならない。
問題は、そのような仕様では constexpr な処理に置き換えられないことである。
このような数列を生成するようなアルゴリズムを、いかにして constexpr で定義するか。
Sprout C++ Library ではこれに対して3つの回答を用意した。
それが sprout::generate と sprout::unfold, および sprout::recurrence である。
なぜ3つもあるかといえば、どのモデルが一般に最適解であるか見いだせなかったからだ。
なお、この記事中のサンプルコードはすべて g++ (GCC) 4.7.2 -std=gnu++0x でコンパイルしている。
sprout::recurrence
まずは sprout::recurrence について。
template<typename Container, typename Generator, typename... Inits> constexpr typename sprout::fixed::result_of::algorithm<Container>::type recurrence(Container const& cont, Generator const& gen, Inits const&... inits);
これは、以下のように使う。
-
- sprout::recurrence でフィボナッチ数列を生成
#include <sprout/algorithm.hpp> #include <sprout/array.hpp> #include <iostream> template<typename T> struct rec_fib { constexpr T operator()(T a, T b) const { return a + b; } }; int main() { constexpr auto arr = sprout::recurrence( sprout::array<int, 30>{}, rec_fib<int>(), 0, 1 ); for (int e : arr) { std::cout << e << ' '; } std::cout << std::endl; }
-
- 出力
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229
ここで gen は、x_n = gen( x_{n-m} .. x_{n-1} ) となるような漸化式である。
rec_fib の場合、x_n = x_{n-2} + x_{n-1} であり、これはフィボナッチ数列の定義と同様である。
inits は初期値であり、gen を呼び出す引数の数は、アルゴリズムに渡した sizeof...(Inits) と同じになる。
なお、inits も結果の列に含まれる。
template<typename T> struct rec_trib { constexpr T operator()(T a, T b, T c) const { return a + b + c; } };
たとえばこのような関数オブジェクトを用意し、初期値に 0, 0, 1 を与えれば、トリボナッチ数列が得られる。
また operator() を Variadic function にすれば、前項までの任意個の和を計算するフィボナッチ数(の拡張)となるだろう。
このように sprout::recurrence は、フィボナッチ数のようなシンプルな漸化式を素直に表現するのに向いている。
しかし個人的には、これをさほど気に入っていない。
一般のプログラムにおいて、あまり汎用的とは考えにくいからだ。
Sprout の初期の実装においては、もともとこの sprout::recurrence が generate という名前だった。
そういった経緯の事情から、recurrence という名前に変更し、今もライブラリに残してある。
sprout::unfold
次に sprout::unfold について。
template<typename Container, typename Generator, typename Init> constexpr typename sprout::fixed::result_of::algorithm<Container>::type unfold(Container const& cont, Generator const& gen, Init const& init);
これは、以下のように使う。
-
- sprout::unfold でフィボナッチ数列を生成
#include <sprout/algorithm.hpp> #include <sprout/array.hpp> #include <sprout/utility.hpp> #include <iostream> template<typename T> struct unf_fib { constexpr sprout::pair<T, sprout::pair<T, T>> operator()(sprout::pair<T, T> const& x) const { return {x.first, {x.second, x.first + x.second}}; } }; int main() { constexpr auto arr = sprout::unfold( sprout::array<int, 30>{}, unf_fib<int>(), sprout::make_pair(0, 1) ); for (int e : arr) { std::cout << e << ' '; } std::cout << std::endl; }
-
- 出力
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229
ここで gen は、ただ一つの引数をとり (現在の値, 次の呼出に与える引数) のペアを返すような関数オブジェクトである。
このようなデザインは、Haskell の unfoldr などに倣ったものである。
ちなみに Haskell の unfoldr は Maybe モナドを返すが、sprout::unfold で同じようなことをやりたい場合は、
無効値をとる型を返す関数オブジェクトと無効値をとる型を格納できるコンテナを用いる必要がある。
なお、この Generator の返値として用いることができるクラスは、デフォルトで pair や tuple などがあるが、
コンセプトを満たすことで独自のクラスを用いることもできる。
-
- generated_value(), next_generator() メンバ関数を持つ。
- generated_value(), next_generator() フリー関数を ADL で呼び出すことができる。
- get<0>(), get<1>() フリー関数を (sprout::tuples::get を含めた) ADL で呼び出すことができる。
以上を上から順にいずれかを満たすクラスを GeneratorResult コンセプトとしている。
これについてはなかなか汎用的なデザインではないかと思う。
ところで Generator については UnaryFunction が求められ、これは悪くはないのだが、場合によっては別の仕様であるほうがやりやすいこともある。
それについては以下。
sprout::generate
最後に sprout::generate について。
template<typename Container, typename Generator> constexpr typename sprout::fixed::result_of::algorithm<Container>::type generate(Container const& cont, Generator const& gen);
これは、以下のように使う。
-
- sprout::generate でフィボナッチ数列を生成
#include <sprout/algorithm.hpp> #include <sprout/array.hpp> #include <sprout/utility.hpp> #include <iostream> template<typename T> struct gen_fib { T a, b; constexpr gen_fib() : a(0), b(1) {} constexpr gen_fib(T a, T b) : a(a), b(b) {} constexpr sprout::pair<T, gen_fib> operator()() const { return {a, gen_fib(b, a + b)}; } }; int main() { constexpr auto arr = sprout::generate( sprout::array<int, 30>{}, gen_fib<int>(0, 1) ); for (int e : arr) { std::cout << e << ' '; } std::cout << std::endl; }
-
- 出力
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229
unfold の場合と異なるのは、ここで gen は引数を取らず (現在の値, 次に呼出すべきジェネレータ) のペアを返すような関数オブジェクトであることだ。
これは std::generate と unfold の合の子のようなデザインである。
Sprout.Random の乱数生成機はこのような Generator のコンセプトを満たすので、sprout::generate と組み合わせて使うことができる。
-
- sprout::generate で [1..6] の整数一様分布の乱数列を生成
#include <sprout/algorithm.hpp> #include <sprout/random.hpp> #include <sprout/array.hpp> #include <iostream> int main() { constexpr auto arr = sprout::generate( sprout::array<int, 30>{}, sprout::random::combine( sprout::default_random_engine(SPROUT_UNIQUE_SEED), sprout::uniform_smallint<int>(1, 6) ) ); for (int e : arr) { std::cout << e << ' '; } std::cout << std::endl; }
-
- 出力
3 2 3 1 5 1 2 5 3 3 2 5 5 4 6 1 2 1 1 6 6 3 6 6 2 6 6 1 1 5
まとめ
ともあれ、これで constexpr でコンパイル時に漸化式や乱数の展開を扱うことができる。
ところで、アルゴリズムができれば今度は Range Adaptor を作りたくなるのが人情である。
たとえば上記のような仕様を満たす generated Range Adaptor を作ることなどは簡単だ。
しかし、STL や Boost のように伝統的なイテレータを念頭に置いた Range のモデルでは、いくらか無駄のある実装にならざるを得ないという問題がある。
"Iterators Must Go" などと言われて久しい(参照:「Iterators Must Go」を訳してみた - Faith and Brave - C++で遊ぼう)が、他方、イテレータベースの実装にすれば既存の様々な処理と連携しやすいこともまた事実である。
D言語の Range などは非常に洗練されていると思うが、あれが C++ においてもベストプラクティスとなりうるかは疑問である。
このあたり悩ましいので、何かあればさまざま拝聴したいところだ。
static データメンバの初期化 - constexpr な場合とそうでない場合
constexpr の間違った使い方。 - C++でゲームプログラミング
この記事へのフォローです。
constexpr static データメンバの場合は、"コンパイル時定数である変数は、宣言と同時に初期化しなければならない" という原則にしたがって、
クラススコープの内側に初期化を書いてやります。
template<typename T> struct X { static constexpr T value = {}; }; template<typename T> constexpr T X<T>::value;
つまり、constexpr の場合は内側の宣言に初期化を書き、そうでない場合は外側に初期化を書かなければならない。
非常に面倒な仕様と思います。
なお Sprout C++ Library では、constexpr が使える場合とそうでない場合双方に対応するために、
SPROUT_STATIC_CONSTEXPR_DATA_MEMBER_INNER および SPROUT_STATIC_CONSTEXPR_DATA_MEMBER_OUTER という二つのマクロを使っています。
//#define SPROUT_CONFIG_DISABLE_CONSTEXPR /* constexpr を無効にするかどうかのオプション。通常はコンパイラに応じて自動的に定義される */ #include <sprout/config.hpp> template<typename T> struct X { SPROUT_STATIC_CONSTEXPR T value SPROUT_STATIC_CONSTEXPR_DATA_MEMBER_INNER({}); // constexpr が有効な場合はこちらで初期化される }; template<typename T> SPROUT_CONSTEXPR_OR_CONST T X<T>::value SPROUT_STATIC_CONSTEXPR_DATA_MEMBER_OUTER({}); // constexpr が無効な場合はこちらで初期化される
見てのとおり非常に面倒です。
C++03コンパイラ をターゲットにしなくてよい開発ならば、全部 constexpr で統一すればよいと思います。
Ceterum autem censeo, VC++ esse delendam. (ともあれ、VC++は滅ぶべきであると考える次第である)
constexpr を使うべき5の理由 - まとめ&リンク集
「constexpr を使うべき5の理由」の連載をひとまず終えたので、記事の一覧をここにまとめておきます。
また、その他の資料や情報へのリンクを載せておきますので、更に興味あるという方は読んでみるのもよいでしょう。
constexpr を使うべき5の理由
なぜあなたは const 修飾よりも constexpr 指定をするべきか。
「市民、あなたは constexpr ですか」
「もちろんです、C++。constexpr であることは市民の義務です」
参照透明な世界に行きたい。
型には TMP、値には constexpr。
その他の資料
下記は、自分が Boost.勉強会で発表したスライドを SlideShare にあげたものです。
こちらでは constexpr の実装技法や落とし穴等を中心に解説しています。
-
- はじめに
- constexprとは?
- constexpr実装技法
- constexprの3大コスト
- constexprライブラリを使ってみる
- まとめ
-
- はじめに
- constexprおさらい
- constexprとTMPの連携
- (続)constexprレイトレーシング
- まとめ
constexpr ライブラリ
constexpr を活用したライブラリです。
ここに挙げているものの他にも面白いライブラリがありましたら、ぜひ報告お願いします。
自作のライブラリ。constexpr に対応したコンテナ、アルゴリズム、乱数、構文解析、レイトレーシング、その他の機能を提供。
「constexpr を使うべき5の理由」の中でもいくつかのコードで使用しています。
id:RiSK 氏によるライブラリ。STL の Non-modifying なアルゴリズムの constexpr 版などを提供。
constexpr ライブラリの先駆けでもあり、Sprout にもその実装の多くを(氏の許可を得て)取り込んでいます。
Ábel Sinkovics 氏による Boost.MPL を拡張するライブラリ。
テンプレートベースながら実装に constexpr を利用しており、Boost にも提案されている。
constexpr 有識者のブログ
CEL の作者である、よく訓練されたしーぷらぷらー id:RiSK 氏のブログ。
constexpr 関数におけるエラーハンドリングなど、興味深い考察を多く書かれています。
Sprout のコミッタかつ Vimmer である id:osyo-manga 氏のブログ。
Sprout を活用した example をはじめ C++ や Vim の豊富な記事を書かれています。
C++標準化委員会メンバーであり、自由ソフトウェア主義者たる江添亮氏のブログ。
constexpr の規格策定の経緯や標準準拠の動作について詳細な情報を書かれています。
Sumant Tambe 氏のブログ。
シンプルなコンパイル時正規表現マッチャーなど、様々なアイディアを取り上げています。