はじめに
昨年の末、新たなVisual C++がリリースされたことにお気づきでしょうか。
- Visual C++ Compiler November 2012 CTP(以下、Nov2012CTP)
CTPとはCommunity Technology Preview、要するにお試し版、正式なupdateまでの"つなぎ"なので実プロジェクトで使うわけにはいかないけども「次版の予告編として提供するから遊んでみてね。ついでに不具合見つけたら教えてくれるとうれしいな♪」的なリリースです。
Nov2012CTPで提供されるのは、コンパイラ本体とヘッダが一本。Visual Studio 2012にadd-inする形式で、CTP単体ではインストールしても無意味です。Visual Studio 2012(無償版:Expressも可)がインストールされた環境で本CTPをインストールするとVisual C++プロジェクト・プロパティのプラットフォーム・ツールセットに追加され、こいつを選択することでコンパイラが切り替わります。
ただし今回のCTPはホントにコンパイラ"だけ"であり、IDEやIntelliSenseは従来のまま。なので、構文エラーを示す波線がところどころに現れるのはご承知おきください。
Nov2012CTPで追加されたのは、VC11(Visual C++ 2012)でサポートできてなかったC++11の機能の中から6つ:
- Raw String Literals
- Explicit Conversion Operators
- Default template Arguments for Function Templates
- Delegating Constructors
- Uniform Initialization
- Variadic Templates
片っ端からざっくりと解説しましょうね。
Raw String Literals:'生'の文字列リテラル
C/C++の文字列リテラルはバックスラッシュ:'\'によって特殊な文字を表現できます。\nで改行、\tでTabとかね。その代わり \ は\\ と表記しなければなりませんが、これが時として煩わしく感じることがあります。例えば正規表現。”バックスラッシュで囲まれた部分文字列”を見つけたいとき、これにマッチする正規表現は\\.*\\です。これを文字列リテラルで記述すると例えば:
regex re( "\\\\.*\\\\" );
です。ちょっとウンザリしますね。C++11ではリテラルにRを接頭することでバックスラッシュによるエスケープを行わない'生'の文字列を書き下すことができます。
regex re( R"(\\.*\\)" );
このように、R"(と)" で囲まれた文字列がリテラルとなり、改行やTab、引用符などもそのまま書き下せます。...それじゃリテラル中に )" を書きたい...そんなアナタのために、終端記号をユーザが指定できます。R"raw(abc"(def)"ghi)raw"のようにR"○×△(からはじめれば)○×△"が終端です。なるほどねー。
Explicit Conversion operators:明示的な変換オペレータ
#include <iostream> using namespace std; class negative { public: negative(int v) : value_(v) {} operator bool() const { return value_ < 0; } private: int value_; }; int main() { negative neg(-3); cout << neg + 123 << endl; // えっ? }
このコード、不思議なことにコンパイル/実行できちゃいます。class negativeであるbegとint値123とを+できるハズがないのに...。これはoperator bool()によってboolへの暗黙の型変換が行われ、bool値がint扱いされて+されるからなんですね。
このような暗黙の型変換を抑止するため、変換オペレータを'explicit'で修飾できるようになりました。引数1つのコンストラクタをexplicit修飾することで暗黙のコンストラクトを抑止するのと同じです。explicitされた変換オペレータは明示的なキャスト(この例では(bool)negやstatic_cast<bool>(neg))が行われない限り、勝手に変換されることはなく、コンパイルエラーとしてくれます。
Default Template Arguments for Function Templates:関数テンプレートにおけるデフォルト・テンプレート引数
<algorithm>に定義された std::sort を用いてコンテナ内の要素をソートする関数を書くことにしましょう。引数はコンテナと比較オブジェクト(ファンクタ)、ただし比較オブジェクトが与えられないときはstd::less<コンテナ要素の型>を使います。従来ならこんな実装になるでしょうね:
template<typename Container, typename Pred> void sort_container(Container& container, Pred compare) { std::sort(begin(container), end(container), compare); } template<typename Container> void sort_container(Container& container) { std::sort(begin(container), end(container), std::less<typename Container::value_type>()); }
関数テンプレートにデフォルト・テンプレート引数が許されないので、比較オブジェクトのアリ版とナシ版とを定義しています。C++11ではデフォルト・テンプレート引数がサポートされるため、こんなコードで実現できます。
template<typename Container, typename Pred = std::less<typename Container::value_type>> void sort_container(Container& container, Pred compare =Pred()) { std::sort(begin(container), end(container), compare); }