Visual C++で使えるC++11
description
Transcript of Visual C++で使えるC++11
身内向けです。 Visual C++で使える C++11の機能を、言語機能、ライブラリに分けて紹介します。
紹介する機能は私が独断と偏見で選んだ一部です。全て紹介するわけではありません。
コンパイラやライブラリのバグや部分対応までいくと作業量大変なのでそこら辺は触れません
内容の正しさには気をつけていますが間違えている可能性もあります。
まえがき
サンプルコードは暗黙に必要なヘッダのインクルード、 using namespace std;をしています。
また、イメージとしてのサンプルで、実際には動かないコードもあります。
ライブラリの初出は所属する名前空間が std::tr1ではなく stdになった初めてのバージョンとします
まえがき
Visual C++ 10.0 (Visual Studio 2010)
VC10
Visual C++ 11.0 (Visual Studio 2012)
VC11
Visual C++ 11.0 Community Technology Preview (Visual Studio 2012)
VC11CTP
Visual C++ 12.0 Preview (Visual Studio 2013 Preview)
VC12PR
Visual C++ 12.0 (Visual Studio 2013)
VC12
Visual C++ 12.0 Community Technology Preview (Visual Studio 2013)
VC12CTP
このスライドでは以下のように表記します
変数の型を右辺式より推論する修飾子はつかない C/C++03までの自動変数を表す autoと互換性がなくなった
auto(VC10)
template <class F, class G, class T>void call(const F& f, const G& g, const T& t) { const auto& temp = f(t); g(temp);}
int main() { auto f = [](int n){return n * n;}; auto g = [](int n){return n + n;}; cout << call(f, g, 10) << endl;}
ヌルポインタを表すリテラル NULLはマクロで 0に置換され、数値と曖昧となる場合がある
nullptr(VC10)
void func(int){}void func(int*){}
int main() { func(10); func(nullptr);}
戻り値を宣言の後ろに記述できる後述の decltypeと合わせるとより便利
戻り値の後置 (VC10)
//int型を返す関数の宣言int hoge();auto foo() -> int;
//void (int)型の関数ポインタを返す関数の宣言void (*f())(int);auto g() -> void (*)(int);
式から型を推論する
decltype(VC10)
template <class T, class U>auto plus(const T& t, const U& u) -> decltype(t + u) { return t + u;}
int main() { vector<double> v; v.push_back(plus(10, 10.0)); const decltype(v) u = v;}
コンパイル時に assertチェックが出来るコンパイル時にチェックできるのは型とコンパイル時定数の 2つ
static_assert(VC10)
int main() { static_assert(sizeof(long) >= 8, "64bit以上環境が必要です "); static_assert(_MCV_VER >= 1600, "VC++10.0以上の VC++コンパイラでなければなりません ");}
従来の参照は正確には左辺値参照右辺値への参照ができるようになった機能としてはこれだけだが、本質は別にある。今回は機能紹介が目的なので省略
右辺値参照 (VC10)
int main() { int a = 10; int& lval_ref = a; //int& ng = 10; int&& rval_ref = 10; //int&& ng = a; const int& clval_ref1 = a; const int& clval_ref2 = 10;}
その場に無名の一時関数オブジェクトを生成する戻り値の省略可能変数のコピーキャプチャ、参照キャプチャ可能
ラムダ式 (VC10)
int main() { vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; vector<int> result; int border = 5; copy_if(v.begin(), v.end(), back_inserter(result), [&border](int it) { return it > border; });}
enumの前方宣言が可能になった要素の整数型を指定できるようになった要素の最後にカンマが付いても良くなった
enum(VC11)
enum weekend : unsigned short;void disp_weekend(weekend w);
enum weekend : unsigned short { SATURDAY, SUNDAY,};void disp_weekend(weekend w) { if(w == SATURDAY) { cout << "SATURDAY" << endl; } else { cout << "SUNDAY" << endl; }}
int main() { dips_weekend(SATURDAY); }
enumにスコープができた暗黙の型変換を禁止する
enum class(VC11)
enum class traffic_light : unsigned int { RED, YELLOW, BLUE};
int main() { traffic_light tl = traffic_light::RED; unsigned int i = static_cast<unsigned int>(tl);}
従来の for文は強いて言うならインデックス for文と言える
範囲ならば何でも、範囲全体を反復処理する
範囲 for文 (VC11)
int main() { for (const auto& it : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) { if(it % 5 == 0) { cout << "buzz\n"; } else if (it % 3 == 0) { cout << "fizz\n"; } else { cout << it << endl; } }}
クラス、または仮想関数に final指定ができるクラスに指定した場合、そのクラスを基底クラスにすることができなくなる
仮想関数に指定した場合、その仮想関数をオーラーライドできなくなる
final(VC11)
class hoge final {};class foo : hoge {}; //エラー
class base { virtual void func() final {}};
class derived : base { virtual void func() {}//エラー};
オーバーライドの意図を明確にするためにできたタイポやオーバーライドのつもりになっているミス (気づきにくい )をエラーとして検出できる
override(VC11)
class hoge { virtual void func1() const {} virtual void func2() const {} void func3() {}};
class foo : hoge { virtual void fumc1() const override {} //エラー virtual void func2() override {} //エラー virtual void func3() override {} //エラー};
引数が 1つのコンストラクタは以前から暗黙な型変換を抑制する explicit指定ができた
型変換演算子にも explicit指定ができるようになった
明示的な型変換演算子 (VC11CTP)
class integer {public: explicit integer(int in) : value_(in) {} explicit operator int() const {return value_;}private: int value_;};
int main() { integer n(42); int m = static_cast<int>(n);}
今まではクラステンプレートにはデフォルトテンプレート引数が指定できたが、関数では無理だった (オーバーロードで同様のことが実現できるため )が、できるようになった
関数テンプレートのデフォルトテンプレート引数 (VC11CTP)
template <class T, class D = default_delete<T>>unique_ptr<T, D> make_unique(T* p, D d = D()) { return {p, forward<D>(d)};}
コンストラクタから同クラスの他のコンストラクタを呼び出すことが可能になる
処理を1ヶ所に纏められる
委譲コンストラクタ (VC11CTP)
class point_xy {public: point_xy() : point_xy(0, 0) {} point_xy(int x, int y) : x_(x), y_(y) {}
private: int x_; int y_;};
今まで引数無しコンストラクタ構文での初期化は関数宣言とみなされたり、初期化リストは配列型や POD型にしか適用できなかった。それらの制限を無くし統一された初期化構文 (初期化リスト構文の拡張 )で初期化できるようになった
統一された初期化構文(VC11CTP)
int main() { string str1{"Hello"}; string str2 = {"World"}; string str3{}; stirng str4 = {};
pair<int, int> p1{10, 20}; pair<int, int> p2 = {10, 20};}
任意の型の引数を任意個取ることができるクラス/関数テンプレートを作ることができる。
Cの可変長引数と比べて型安全である
可変長テンプレート引数(VC11CTP)
void print(){}
template <class T, class... Args>void print(const T& t, Args&&... args) { cout << typeid(T).name() << "\t:\t" << t << endl; print(args...);}
int main () { print("hoge", 42, 'c', 3.14, true);}
初期化リストに専用の型が出来た。これを引数にとるコンストラクタを定義することでユーザー定義型でも初期化リストが使えるようになった。
初期化リスト (VC12PR)
int sum(initializer_list<int> li) { return accumulate(li.begin(), li.end(), 0);}
template <class T, class U>pair<T, U> create_pair(T t, U u) { return {t, u}; //どちらかと言うと統一された初期化構文}
int main() { auto result = sum({9, 8, 7, 6}); auto p = create_pair("hello", 3.14); vector<double> v = {1.0, 2.0, 3.0};}
非静的データメンバを宣言と同時に初期化出来る C#などでは普通にできるコンストラクタで初期化すると上書きされる
メンバ初期化子 (VC12)
class person {public: person(const string& name, int age) : name_(name), age_(age) {} int age() const {return age_;} const string& name() const {return name_;}private: string name_ = "noname"; int age = -1;};int main() { person p; assert(p.age() == -1); person p2{"tom", 20}; assert(p.name() == "tom");}
コンパイラによって自動生成される関数が既定の動作であることを明示する
自動生成される関数へのdefault指定(VC12)
class hoge {public: hoge() = default; hoge(const hoge&) = default; ~hoge() = default; hoge& operator=(const hoge&) = default; //VC12の時点で move ctor/assignは自動生成されない};
望まない型変換や関数テンプレートのインスタンス化を抑止できる
自動生成される関数の生成を抑止できる
関数の delete指定 (VC12)
template <class T>void f(){}
//char型だけはダメtemplate <>void f<char>() = delete;
//long longより小さい型はダメvoid g(long long){}void g(long) = delete;
class hoge {public: hoge(const hoge&) = delete; hoge& operator=(const hoge&) = delete; //newで割り当てられないようにする void* operator new(size_t) = delete;};
typedefは型にしか別名をつけられないテンプレートに対する別名を usingを用いた構文で可能にした
usingを用いた構文で型にも別名を付けられる
別名テンプレート (VC12)
int add(int, int){}int sub(int, int){}
template <class T>using my_vector = vector<T, my_allocator<T>>;
int main() { using func_t = int (*)(int, int); my_vector<func_t> v = {add, sub};}
今までは暗黙にコンパイラに自動生成される関数はコンストラクタ、コピーコンストラクタ、コピー代入演算子、デストラクタの 4つだったがC++11ではムーブコンストラクタ、ムーブ代入演算子の 2つが増え、全部で 6つになった
サンプル無し
ムーブコンストラクタ・ムーブ代入演算子の自動生成 (VC12CTP)
オブジェクトが左辺値か右辺値かによってメンバ関数を呼び分けられるようになる
メンバ関数の参照修飾子 (VC12CTP)
struct hoge { void func() & { cout << "lvalue\n"; } void func() && { cout << "rlvalue\n"; }};
int main() { hoge h; h.func(); hoge().func();}
ユーザーが任意の型のリテラルを表すサフィックスを定義できる
ユーザー定義リテラル(VC12CTP)
string operator ""_s(const char* str, size_t size) { return {str, size};}
int main() { cout << "hello"_s.size() << endl;}
変数や関数がコンパイル時定数、コンパイル時計算可能である (結果として副作用がなく、参照透過性があることを保証している )ことを表す
constexpr(リテラル型とコンストラクタ除く )(VC12CTP)
constexpr int factorial(int n) { return n == 0 ? 1 : n * factorial(n - 1);}
int main() { array<int, factorial(4)> ar;}
関数が例外送出するか有無を指定できる式が例外を投げるか判定できる演算子
noexcept(VC12CTP)
class integer {public: integer(int value) : value_(value) {} int get() const noexcept {return value_;}private: int value_;};
int get(const integer& in) noexcept(noexcept(in.get())) { return in.get();}
int main() { integer n{42}; cout << get(n) << endl;}
alignof 変数や型のアライメントを取得する alignas 変数宣言の際、アライメントを指定する
alignof/alignas(VC12CTP)
int main() { alignas(int) unsigned char c[32]; alignas(4) int a; constexpr int int_align = alignof(int);}
C++11 VC++の書き方 バージョン
alignas(x) __declspec(align(x)) VC7
alignof(T) __alignof(T) VC7
thread_local __declspec(thread) VC10
[[noreturn]] __declspec(noreturn) VC7
独自拡張としてある機能
制限を無くした union属性 char16_t/char32_t inline namespace継承コンストラクタ thread_local Unicode文字列リテラルリテラル型に対する constexpr
VC12CTP以降になるC++11の機能
始めに新しく登場したヘッダを紹介します。次に既存のヘッダに追加されたクラス、関数、型など紹介します
全て紹介するわけではありません各クラスのメンバについては触れません関数などのオーバーロードや事前 /事後条件や計算量や引数 /戻り値型の要求などについては触れません
まえがき
ビット数が規定された整数型の typedefや、マクロを定義している
intN_t(Nビットサイズの符号あり整数型 ) uint_leastN_t(少なくとも Nビットサイズのある符号なし整数型 )
PTRDIFF_MAX(std::ptrfiff_tの最大値 )など
<cstdint>(VC10)
単方向リスト (listは双方向リストで、ノードに 2つのポインタを持つが、こちらは 1つ )
C言語で単方向リストを実装する場合と比べて、空間計算量も時間計算量もゼロオーバーヘッドであるよう設計されている
<forward_list>(VC10)
擬似乱数を扱うための、擬似乱数生成器、分布生成器、真の乱数生成器、シード数列などが定義されている
mt19937(パラメータ定義済み 32bitメルセンヌツイスターエンジン )や、 linear_congruential_engine(線形合同法エンジン )などの擬似乱数生成器、 uniform_int_distribution(一様整数分布生成器 )、 normal_distribution(正規分布生成器 )などがある
<random>(VC10)
型の特性、操作を行うメタ関数が定義されている
conditional(コンパイル時条件式 )、 is_same(2つの型が同じ型か判定する )、 coomon_type(共通の型を取得する )などがある
<type_traits>(VC10)
setと比べ、キーの順序ではなくキーの hash値に基いて格納される連想配列
ソートはされておらず、順序は有意ではないが検索が setよりも高速なため、ソートされている必要がないのならこちらを使うと良い
<unordered_set>(VC10)
mapと比べ、キーの順序ではなくキーの hash値に基いて格納される連想配列
ソートはされておらず、順序は有意ではないが検索がmapよりも高速なため、ソートされている必要がないのならこちらを使うと良い
<unordered_map>(VC10)
vector<string>のような要素とコンテナで両方にメモリ確保が必要になった場合、コンテナと要素で同じアロケータからメモリ確保するためのアロケータアダプタを提供する。
<scoped_allocator>(VC11)
変数へのスレッド間でデータをやり取りするための基本的な操作であるアトミック操作を提供する。
分解不能読み書きが行える。マルチスレッドプログラミングについて熟知していればmutexを用いるよりパフォーマンスが向上する可能性があるが、扱いが難しく逆にパフォーマンスが劣化する可能性もあるので、mutexのパフォーマンスが問題にならない限り使用しなくて良い
<atomic>(VC11)
スレッド間で安全にデータをやり取りするための排他制御を提供する
排他制御mutex、それを RAIIで扱えるlock_guard、指定された関数を 1度だけ呼び出す call_onceなどがある
<mutex>(VC11)
マルチスレッドプログラミングのデザインパターンの 1つである future/promiseパターンを実現する機能を提供する
データや例外を設定する promise、データや例外を取得する future、 future/promiseを簡単に行えるようラップした asyncなどがある
<future>(VC11)
all_of, any_of, none_of find_if_not copy_n, copy_if move, move_backward suffle is_partitioned partition_copy, partition_point is_sorted, is_sorted_until is_heap, is_heap_until minmax, minmax_element is_permutation
<algorithm>(VC10)
function, bad_function_call bind, is_bindexpression, is_placeholder,
placeholders::_1, placeholders_2, placeholders::_N, mem_fn
reference_wrapper, ref, cref hash
<functional>(VC10)
deque◦ cbegin, cende, crbegin, crend◦ shrink_to_fit◦ emplace, emplace_back, emplace_front
<deque>(VC10)
set◦ cbegin, cende, crbegin, crend◦ emplace, emplace_hint
multi_set◦ cbegin, cende, crbegin, crend◦ emplace, emplace_hint
<set>(VC10)
map◦ cbegin, cende, crbegin, crend◦ at◦ emplace, emplace_hint
multi_map◦ cbegin, cende, crbegin, crend◦ at◦ emplace, emplace_hint
<map>(VC10)
queue◦ emplace, swap◦ reference, const_reference
priority_queue◦ emplace, swap◦ reference, const_reference
swap
<queue>(VC10)
basic_string◦ cbegin, cende, crbegin, crend◦ shrink_to_fit◦ pop_back, back, front
stoi, stol, stoul, stoll, stoull, stof, stod, stold
<string>1(VC10)
unitilialized_copy_n
shared_ptr, unique_ptr, weak_ptr, enable_shared_from_this, bad_weak_ptr, owner_less, default_delete, addresso
make_shared, allocate_shared, static_pointer_cast, dynamic_pointer_cast, const_pointer_cast
pointer_safety, get_pointer_safety, declare_reachable, undeclare_reachable, declare_no_reachable, undeclare_no_reachable
<memory>1(VC10)
<memory>2(VC11) align, pointer_traits allocator_traits, allocator_arg_t,
allocator_arg, uses_allocator
forward, move(VC10) tuple_size, tuple_element, get(VC10) move_if_noexcept(VC11) declval, piecewise_constrcut_t,
piecewise_constrcut(VC11)
<utility>(VC10, VC11)
nested_exception get_unexpected exception_ptr, current_exception,
rethrow_exception, make_exception_ptr throw_with_nested, rethrow_if_nested
<exception>(VC11)
HUGE_VALF, HUGE_VALL, INFINITY, NAN FP_INFINITE, FP_NAN, FP_NORMAL,
FP_SUBNORMAL, FP_ZERO FP_FAST_FMA, FP_FAST_FMAF,
FP_FAST_FMAL FP_ILOGB0, FP_ILOGBNAN MATH_ERRNO, MATH_ERREXCEPT math_errhandling
<cmath>(VC12PR)
<cmath>◦ asinh, acosh, atanh◦ exp2, expm1, log1p, log2◦ ilogb, logb, scalbn, scalbln◦ cbrt, hypot◦ erf, erfc, tgamma, lgamma◦ trunc, round, nearbyint, rint, lrint, llrint◦ remainder, remquo◦ copysign, nan, nextafter, nexttoward◦ fmax, fmin, fdim, fma◦ fpclassify, isfinite, isinf, isnan, isnormal, signbit◦ float_t, double_t,
※グローバル領域には存在する。 std名前空間に所属していない
VC12PR時点で対応していないC++11のライブラリ
一般化されたラムダキャプチャー (VC12CTP) auto指定での一般関数の戻り値の型推論
(VC12CTP)多相ラムダ (VC12CTP) decltype(auto)(VC12CTP) STLのユーザー定義リテラル対応 (VC12CTP)
言語機能
make_unique(VC12) <type_traits>の using alias(例えば
make_unsigned_t, decay_tなど )(VC12) begin()/cend()/rbegin()/rend()/crbegin()/
crend()(VC12)多相ファンクタ (VC12) async/await(VC12CTP)
ライブラリ