Visual C++ 12.0 CTPと比べて新しく対応したC++11/14/1zの新規の機能を紹介します。
コア言語
- Terse range-based for
訳すなら簡便な範囲for文、って感じでしょうか? C++14の次の規格で提案されている機能で、正式に入ることは決定していませんが、ほぼ入ると思われます。
(2014/12/13追記 C++1zの機能から取り除かれたようです)
これは範囲for文の型宣言を省略した時に、auto&&
と型を書いたように振る舞う機能です。
#include <iostream> #include <vector> int main() { std::vector<int> v = {1, 2, 3, 4, 5}; for (i : v) { // for (auto&& i : v)と同等になる std::cout << i << std::endl; } }
- 汎用ラムダキャプチャー
C++11の時の暫定的なラムダキャプチャーの仕様から、統一的な記法でラムダキャプチャーを書けるようになりました。
#include <memory> #include <iostream> int main() { auto ptr = std::make_unique<int>(); int a = 0; [p = std::move(ptr), &a = a] { std::cout << *p << a; }(); }
ラムダ導入子(lambda introducer)に左辺 = 右辺
という風に書きます。左辺にはラムダの中で使う変数(実装的にはラムダ式で作られる関数オブジェクトのメンバ変数)の名前、右辺にはキャプチャするラムダの外の変数を書きます。複数キャプチャする場合はカンマで区切ります。参照で受け取る場合は左辺の変数名の左に&をつけます。左辺と右辺は別のスコープの別の変数のため同じ名前をつけても問題ありません。
- 2進数リテラル
int main() { static_assert(0b11 == 3, ""); }
- スレッドローカル変数
スレッドごとに異なる変数を定義することができます。
#include <iostream> #include <mutex> #include <thread> #include <vector> namespace { std::mutex mutex; } void test_thread_local(int n) { static int sval = 0; thread_local int tval = 0; int val = 0; std::lock_guard<std::mutex> lock{mutex}; sval += n; tval += n; val += n; std::cout << "static:" << sval << " thread_local:" << tval << " local:" << val << std::endl; } void f() { for (int i = 0; i < 2; ++i) { test_thread_local(1); } } int main() { std::vector<std::thread> threads; for (auto i = 0U; i < 3U; ++i) { threads.emplace_back(std::thread{f}); } for (t : threads) { t.join(); } }
実行結果
static:1 thread_local:1 local:1 static:2 thread_local:2 local:1 static:3 thread_local:1 local:1 static:4 thread_local:2 local:1 static:5 thread_local:1 local:1 static:6 thread_local:2 local:1
- ユーザ定義リテラル(と標準ライブラリの対応)
機能の詳しい説明は以下を参照
#include <string> constexpr unsigned long long int operator""_k(unsigned long long int value) { return value * 1000; } int main() { using namespace std::string_literals; "hoge"s.length(); static_assert(1_k == 1000, ""); }
- noexcept
Visual C++ 12.0 CTPでもnoexceptは入ったが、あちらは部分的な実装で、関数の例外指定(しかも 定数式が受け取れない)のみとなっている。こちらは完全な実装となっており、定数式も受け取れますしnoexcept演算子も使えます。
int main() { static_assert(noexcept(1 + 1), ""); }
- inline namespace
inline namespaceで宣言された名前にはその名前空間名を省略してアクセスすることが出来る。
inline namespace hoge { int a; } int main() { hoge::a; a; }
char16_t
、char32_t``と、リテラルのプレフィックス
u8、
u、
U`が追加されました。
int main() { char const* u8str = u8"aaa"; char16_t const* u16str = u"bbb"; char32_t const* u32str = U"ccc"; }
標準ライブラリ
u16string
、u32string
、string_literals
前述のchar16_t、char32_tに対応するbasic_string方が定義されました。
対応するbasic_stringを得ることが出来るユーザ定義リテラルs
も実装されました。
#include <string> int main() { char const* u8str = u8"aaa"; char16_t const* u16str = u"bbb"; char32_t const* u32str = U"ccc"; std::string s1 = u8str; std::u16string s2 = u16str; std::u32string s3 = u32str; using namespace std::string_literals; "ddd"s.length(); u8"eee"s.length(); }
- ユーザ定義リテラル対応
前述の<string>
の他にも<chrono>
と<complex>
がユーザ定義リテラルに対応しました。
- null forward iterator
C++14において、Forward Iteratorをデフォルト初期化した場合、どこも指さないnull iteratorになることが定められました。それに対応しました。参考
C++14 ヌル前方イテレータの規定 - Faith and Brave - C++で遊ぼう
- quoted
<iomanip>
にstd::quotedが追加されました。これはストリームに文字列を出力する際にダブルクオーテーションで囲む機能、ストリームから文字列を取得する際にダブルクオーテーションで過去まわれた文字列を1つの文字列としてダブルクオーテーションを除いて取得できる機能です。C++14です。
#include <iostream> #include <iomanip> #include <sstream> int main() { std::string s; std::istringstream iss{"\"hello world\""}; iss >> std::quoted(s); std::cout << s << std::endl; // hello world std::cout << std::quoted("hello world") << std::endl; // "hello world" }
C++14でstd::set
、std::map
の以下のメンバ関数にメンバ関数テンプレートが追加されました。
- find()
- count()
- lower_bound()
- upper_bound()
equal_range()
コンパイル時整数シーケンス
<utility>
にstd::integer_sequence
とこれを生成するstd::make_integer_sequence
、integer_sequenceのStd::size_tの特殊化であるstd::index_sequence
とこれを作成するstd::make_index_sequence
、テンプレートパラメータに渡された方の数を得られるstd::index_sequence_for
が追加されました。コンパイル時にインデックスを伴う操作によく使われ、tupleやコンパイル時array等の操作関数で良く使わます。
exchange
<utiliy>
にstd::exchange
が追加されました。これは第1引数で受け取った変数を第2引数で受け取った値で代入し、古い値を返す関数です。1度しか状態が変化しない変数などが簡潔に書けるようになります。
- 2つめの範囲を受け取るアルゴリズムに2つ目の範囲の終端を受け取る版を追加
タイトル通りですが、今までは2つの範囲が等しいサイズかみていませんでした。2つ目の範囲のほうが1つ目の範囲よりサイズが小さい場合、未定義の動作を起こしてしまいます。そこで2つ目の範囲の終端を受け取るオーバーロードが追加されました。
#include <algorithm> #include <array> #include <iostream> int main() { std::array<int, 3> a1 = {1, 2, 3}; std::array<int, 4> a2 = {1, 2, 3, 4}; std::cout << std::boolalpha; std::cout << std::equal(a1.begin(), a1.end(), a2.begin()); // true std::cout << std::equal(a1.begin(), a1.end(), a2.begin(), a2.end()); // false }
get<T>
とtuple_element_t
C++11ではインデックスを指定して値を取得するget<std::size_t>
がありましたが、新たに型を指定して値を取得するgettuple_element<I, T>::type
のエイリアスであるtuple_element_t
も追加されました。
未実装の機能
パッと思いついたもので不完全です
- constexpr(C++11/14)
- Attribute
- 変数テンプレート
- initializer_listによるaggregate初期化の制限緩和
- 標準ライブラリのconstexpr対応
- 桁区切り
- SFINAE式
疲れた……