正規表現
C++で正規表現を使用するためのツールがサードパーティーから数多く出ていますが、標準C++ライブラリとの統合を高いレベルで実現しているものはほとんどありません。正規表現がC++に直接追加されたことにより、STLの一部を構成するアルゴリズムで正規表現の実行結果を使用したり、さまざまなコンパイラでコンパイルできるコードを記述できるようになりました。
正規表現ライブラリの実装は、C++標準のbasic_string
クラスに似ています。TR1の正規表現ライブラリのうち、最も重要なクラスはbasic_regex
で、このクラスは正規表現をラップし、char
またはwchar
のどちらの文字型を使うかをbasic_regex
のテンプレートパラメータで指定します。basic_string
と同様に、typedef
ではchar
版およびwchar
版のbasic_regex
があらかじめ定義されています。basic_regex
クラスは、正規表現文字列と、大文字小文字の区別などの振る舞いや、使用する正規表現言語(basic、extended、ECMAScript、awk、grep、egrepをすべてサポート)を指定するフラグに基づいて正規表現オブジェクトを生成し、このオブジェクトが、ターゲット文字列と共にいずれかの正規表現テンプレート関数に渡されます。
利用できるテンプレート関数はregex_match
、regex_search
、regex_replace
の3つです。regex_match
関数では、ターゲット文字列が、渡されたbasic_regex
オブジェクトに一致しているかを判定します。regex_search
関数は、正規表現に一致するテキストがターゲット文字列内にあるかどうかを判定し、必要な場合には、match_results
オブジェクトに正規表現キャプチャグループを割り当てることができます。残るregex_replace
関数では、正規表現の実行結果に基づいて文字列を置き換えることができます。
下記のサンプルコードでは、電子メールアドレスの妥当性確認を行う、ごく単純な正規表現を2つの文字列定数に対して実行しています(ここでのポイントは正規表現の内容ではありません。実際に電子メールアドレスの妥当性確認を行うには、このサンプルでは単純すぎます)。この例では、正規表現がターゲット文字列と一致するかどうかを出力します。
#include <regex> #include <iostream> #include <string> basic_regex<char> regex("[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}", basic_regex<char>::icase); cout<< std::boolalpha << regex_match("GoOD@DOMAIN.COM", regex) << std::endl; cout<< std::boolalpha << regex_match("@DOMAIN.COM", regex) << std::endl;
関数オブジェクト
関数オブジェクトは、以前にDelegate
クラスを使ったことのあるC++/CLI開発者には馴染みのあるものでしょう。関数オブジェクトは型安全である関数ポインタを提供し、このポインタは、関数実行の一環でアクセスしなければならない追加データも含むことができます。型安全ではない生の関数ポインタとは異なり、TR1関数テンプレートでは、関数を戻り値の型とパラメータによって定義することができ、このシグネチャを満たす関数についてはテンプレートインスタンスの一部としてインスタンス化し、キャストせずに呼び出すことができます。以下のコードは関数オブジェクトを使用して関数を呼び出す方法を示しています。
bool PrintData(int i, double d){ cout << i; cout << endl; cout << scientific << d; cout << endl; return true; } { function<bool (int, double)> myPrint(PrintData); bool res = myPrint(1, 2.0); }
関数オブジェクトの明らかなメリットは、キャストの必要がないことです。この例のmyPrint
オブジェクトは、複雑で危険性もある関数ポインタへのキャストを使わずにPrintData
関数を呼び出すことができます。
その他の追加
TR1のアップデートには、包括的な乱数生成ライブラリも含まれています。TR1に含まれる乱数生成スキーマとしては、bernoulli_distribution
、binomial_distribution
、exponential_distribution
、gamma_distribution
、geometric_distribution
、normal_distribution
、poisson_distribution
などがあります。分布クラスは、TR1ライブラリに含まれているlinear_congruential
やmersenne_twister
などの乱数生成アルゴリズムによって使用されます。次のコードの抜粋は、mersenne_twister
アルゴリズムとgamma_distribution
を使った乱数生成の例を示しています。
using namespace std::tr1; ... //use TR1 typedef mt19937 for Mersenne twister algorithm mt19937 randomAlg; gamma_distribution <double> randomDist; double d = randomDist(randomAlg);
TR1には、新たにunordered_set
、unordered_map
、unordered_multimap
という配列コレクションが加わっています。型名からわかるとおり、この3つのコレクションは、保守するシーケンスを順序どおりに並べないという点で、既存のSTLセットやマップコレクションと異なっています。整列しないことのメリットは、要素の挿入、削除、配置のコストがまったくないか、1回の操作で済むということです(つまり、コレクションサイズの増大に応じて計算のコストが増えることはありません)。反対に、整列しないことによる主なデメリットは、コレクションの同一性の判断が難しくなるという点です。同じ要素を含むコレクションでも、対応する要素が異なる場所に配置されている場合があるからです。
まとめ
今回のTR1アップデートは、C++0xの登場に向けた1ステップであり、標準C++の著しい進化を示すものです。この進化によって、C++言語が当面のあいだは強力で実用的、かつ時代に即したものであり続けることは確かです。TR1はマネージド言語のプログラマが期待するさまざまなメリットと機能をC++にもたらし、ソフトウェア業界がこれまで行ってきたC++コードへの多額の投資をこれからも支えていくことになるでしょう。
Visual C++ 2008機能パックにおけるTR1アップデートのリリースは、Microsoftが引き続きVisual C++製品への投資とサポートを行うことの意思表示であり、同時に、まだ何年かはネイティブコードの開発者が仕事にありつけるということでもあります。