C++11, C++14, C++17 新機能まとめ ～使いそうなものだけ

久しぶりにC++（VC14/15, VisualStudio2015/2017）を触ることになったので、最近のC++について勉強してみた。
「使いそう」、「使うといいことあるかも」、「少なくとも読めるようにはなっておきたい」という新機能を中心に列挙しておく。

各種コンパイラの実装状況については 『[コンパイラの実装状況 - cpprefjp C++日本語リファレンス](https://cpprefjp.github.io/implementation-status.html)』が詳しい。VS2019の実装状況までちゃんと書かれている。感謝 :pray: 

※以下、ソースコードは各参照ページより引用

## C++11
参考: [今すぐに使いたいC++11の新機能](http://minus9d.hatenablog.com/entry/20130815/1376557665)

### nullptr

[C++11 では NULL ではなく nullptr を使う](http://program.station.ez-net.jp/special/handbook/cpp/syntax/nullptr.asp)

```c++:nullptrの記述パターンをいくつか挙げる
// こうではなく
SetDescription(buffer, (void*)NULL);
// このように書くべき
SetDescription(buffer, nullptr);

// ポインタの初期化
char* p = nullptr;

// 条件式
if (p == nullptr){
	:
}
```

### 統一初期化記法(Uniform Initialization)

[C++11 Universal Initialization は、いつでも使うべきなのか](http://qiita.com/h2suzuki/items/d033679afde821d04af8)

こんな感じでC#っぽく書ける。

```c++
int x { 3 };
int a[] { 0, 1, 2, 3 };
struct S1 { int a, b; } s { 0, 1 };
std::vector<int> v { 0, 1, 2, 3 };
```

pairやmapの初期化も簡潔に書ける。

```c++
pair<int, double> p { 1, 2.3 };
map<string, int> m {{"aaa", 10}, {"bbb", 20}, {"ccc", 30}};
```

### 範囲ベースの for-loop

[範囲ベース for ループ](http://vivi.dyndns.org/tech/cpp/range-for.html)

```c++:参照を使えば要素の書き換えも出来る
int ar[] = {3, 1, 4, 1, 5, 9};
for(int &x : ar) {
  if( x == 1 )            // 値が１だったら
    x = 123;           // 123 に書き換える
}
```

```c++:型推測autoも使える
std::vector<int> v{1, 2, 3, 4, 5, 6, 7};
for(const auto& x : v) {
  std::cout << x << "\n";
}
```
```c++:変更するならユニバーサル参照(auto&&)で
for(auto&& x : v) {
  x += 2;
}
```

上の auto&& の例は『ユニバーサル参照』なので、左辺値が与えられれば x は左辺値参照に、右辺値が与えられれば x は右辺値参照になる。
[C++のムーブと完全転送を知る - Fixstars Tech Blog /proc/cpuinfo](http://proc-cpuinfo.fixstars.com/2016/03/c-html/)
[range-based for loopsの要素の型について - Qiita](https://qiita.com/rinse_/items/cdfce8aa6a685a8ebe0c) 最後の方の「2016/5/4 追記」に書かれている使い分けの説明がとってもいい。

### 右辺値参照
大データを扱うクラスを自作する時には、（可能なら）ムーブコンストラクタ・ムーブ代入演算子を定義しておくべきかも。

[C++0x の右辺値参照がこんなに難しいわけがない](http://d.hatena.ne.jp/osyo-manga/20101117/1289958984)
[本当は怖くないムーブセマンティクス](http://yohhoy.hatenablog.jp/entry/2012/12/15/120839)
[C++のムーブと完全転送を知る](http://proc-cpuinfo.fixstars.com/2016/03/c.html)
[C++高速化](https://heavywatal.github.io/cxx/speed.html) 詳細な実験が素晴らしすぎる(^^)
[なぜ std::vector<> は noexcept でない move constructor を呼ばないのか - Qiita](https://qiita.com/kei10in/items/00f65e68a3d08093aceb) 可能なら noexcept を付けておくべきという話。

```c++:ムーブコンストラクタとムーブ代入演算子
Pointer(Pointer&& f) noexcept {
    this->ptr = f.ptr;    // ポインタをコピー
    f.ptr = nullptr;      // ムーブ元はnullptrでクリア
}
Pointer& operator=(Pointer&& rhs) noexcept {
    if (this == &rhs) return;
    delete this->ptr;       // ムーブ先のptrをdeleteしてから
    this->ptr = rhs.ptr;    // ポインタをコピー
    rhs.ptr = nullptr;      // ムーブ元はnullptrでクリア
    return *this;
}
```

### 各種コンテナに追加されたemplace系メソッド

vectorなどのコンテナにユーザー定義クラスを格納する場合には、なるべくemplace系メソッドを使う。

```c++:要素を追加する例
std::vector<MyLargeClass> v;

// 従来通り push_back() を使うと、コンストラクタ＋コピー(orムーブ）＋デストラクタ が走る
v.push_back(MyLargeClass(1, 2));

// emplace_back()を使うと コンストラクタ しか走らないのでとても効率が良い
v.emplace_back(1, 2);             // MyLargeClassのコンストラクタ引数を渡すことに注意
```

[【C++】emplace_back/emplaceとは何か【処理効率やpush_backとの違い】| MaryCore](http://marycore.jp/prog/cpp/emplace-functions/)

### スマートポインタ ```unique_ptr<T> shared_ptr<T> weak_ptr<T>```

非常に有用。でも、性質をよく理解していないと逆に危険。
[C++11スマートポインタ入門](http://qiita.com/hmito/items/db3b14917120b285112f)

```cpp:unique_ptrの使用例
// 普通に使う例
std::unique_ptr<Gdiplus::Bitmap> bitmap(Gdiplus::Bitmap::FromFile(filePath));
if (bitmap == nullptr) return false;

// 配列を確保する例 (後者はC++14で追加された make_unique()を使用する例）
std::unique_ptr<byte[]> bmpHeader(new byte[sizeofHeader]);
std::unique_ptr<byte[]> bmpHeader = std::make_unique<byte[]>(sizeofHeader);

// delete以外の解放メソッドを使う場合の例 その1
std::unique_ptr<ColorPalette, decltype(free)*> palette((ColorPalette*)malloc(paletteSize), free);

// その2 ※後述の型エイリアスを使って記述
using FILE_UPTR = std::unique_ptr<FILE, decltype(&fclose)>;
FILE_UPTR fp(_tfopen(filePath, ("wb")), fclose);
```

### 型エイリアス
[typedef は C++11 ではオワコン](http://qiita.com/Linda_pp/items/44a67c64c14cba00eef1)

```c++
typedef void (*f)(int, char);    // typedefは分かりづらい
using f = void (*)(int, char);   // 型エイリアスはナイス！ C#っぽい。 
```

```c++
// テンプレート化との相性もGood!
template<class Value>
using dict = std::map<std::string, Value>;
```

### 関数のdefault／delete宣言

[関数のdefault／delete宣言](http://cpprefjp.github.io/lang/cpp11/defaulted_and_deleted_functions.html)

```c++:暗黙定義される関数を『実装はdefaultのまま』virtual/inline化することが出来たり
class X {
public:
  // 暗黙定義される挙動をする、
  // 仮想関数のデストラクタを定義する
  virtual ~X() = default;

  // 暗黙定義される挙動をする、
  // インライン関数のコピーコンストラクタを定義する
  inline X(const X&) = default;
};
```

```c++:暗黙定義される関数をdeleteすることも
class X {
public:
  // コピーを禁止し、ムーブを許可する
  X(const X&) = delete;
  X& operator=(const X&) = delete;

  // 特殊メンバ関数を明示的に定義もしくはdeleteした場合、
  // それ以外の特殊メンバ関数は明示的に定義もしくはdefault宣言しなければ
  // 暗黙定義されない
  X(X&&) = default;
  X() = default;
  X& operator=(X&&) = default;
};

int main()
{
  X x1;
//X x2 = x1;  // コンパイルエラー！Xのコピーコンストラクタはdelete宣言されている
  X x3 = X(); // OK : ムーブコンストラクトはできる

  X x4;
//x4 = x1;    // コンパイルエラー！Xのコピー代入演算子はdelete宣言されている

  X x5;
  x5 = X();   // OK : ムーブ代入はできる
}
```

### 可変個引数テンプレート（Variadic Templates）

[可変値引数テンプレート(MSDN)](https://msdn.microsoft.com/ja-jp/library/dn439779.aspx)

```c++:可変長引数を受け取るテンプレート関数
template <typename... Arguments>
int fname(Arguments... args);
```

```c++:具体的な例
template<typename... Arguments>
// const, &, * などの修飾も可能
void tfunc(Arguments&&... args)
{
    // sizeof...で引数の個数も取得出来る
    const unsigned numOfArgs = sizeof...(Arguments);

    // args... で他の関数に渡せる
    size_t size = std::snprintf(buffer, 0, format, args...)

    // std::forwardを使って完全転送
    helper_func(p, std::forward<Arguments>(args));
}
```

[C++のムーブと完全転送を知る](http://proc-cpuinfo.fixstars.com/2016/03/c.html)

## C++14

### constexpr ※constant expression (定数式)
コンパイル時定数とコンパイル時処理。C++11から導入され、C++14で大幅に制限が緩和された。
~~しかし、VC14はまだC++11相当の機能しか実装されていないようだ。~~ 
VC14/15(VS2015/2017)でも概ね実装された。

[constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ](http://www.slideshare.net/GenyaMurakami/onstexprcpu) 

constexpr指定の変数 ＝ コンパイル時定数

```c++:constexpr指定の変数
constexpr unsigned N = 10; // コンパイル時定数は配列のサイズやテンプレート引数として使用可能
std::array<int, N> arr = {{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }};
```

constexpr 指定の関数 ＝ コンパイル時に（も）呼出可能

```c++:constexpr関数
template<typename T>
constexpr T square(T const& t) { return t * t; }

// コンパイル時定数を求めることができる
constexpr int s = square(16);
static_assert(s == 256, "");
```

[constexpr関数の制限緩和](https://cpplover.blogspot.jp/2014/10/c14-constexpr.html)

```c++:VC14/15(VS2015/2017)も対応済み
template < typename T >
constexpr T sqrt(T s)
{
	T x = s / 2.0;
	T prev = 0.0;

	while (x != prev) {
		prev = x;
		x = (x + s / x) / 2.0;
	}
	return x;
}
```

[constexpr](http://cpprefjp.github.io/lang/cpp11/constexpr.html)

### ラムダ式
C++14で機能強化。

[C++14 のラムダ式 完全解説](http://d.hatena.ne.jp/gintenlabo/20130516/1368711542)

```cpp:コード例
// ラムダ式を受け取れる関数を定義
void ReadImage(std::string& filePath, const std::function<void(double)>& func)
{
	// 画像をOpenしたとして、

	// 各画素でループ
	for (int y = 0; y < image.Height(); y++) {
		for (int x = 0; x < image.Width(); x++) {
			// 渡された func を呼び出す
			func(image.GetAt(x, y));
		}
	}
}

// 上記関数にラムダ式を渡す
// [&] : 外部のローカル変数を参照でキャプチャする
// (double v): 各画素値がfuncの引数 v に与えられる ※auto も使える
double total(0.0);  // 輝度値の積算
ReadImage("test.jpg", [&](double v) {
	total += v;
});
```

備考: 上記は std::function でラムダを受け取っているが、template化した方が速いようなので、呼び出す回数が多い場合には要検討。

```c++:上のをtemplate化
template<typename TFunc>
void ReadImage(std::string& filePath, const TFunc& func)
{
  // 中身は全く同じ
}
// 呼び出し方も全く同じ
```

参考: [VS2017でのパフォーマンス実験結果およびソースコード](https://gist.github.com/leon-joel/84bf2f06b2ccaf63210e348ab7e40c2f) main()の先頭付近参照
参考: [C++11 autoはstd::functionより高速 – Hossy](http://www.ngc.is.ritsumei.ac.jp/~hossy/2015/07/c11-auto%E3%81%AFstdfunction%E3%82%88%E3%82%8A%E9%AB%98%E9%80%9F/)
参考: [Maraigue風。:\[C++11\] std::functionとは](http://blog.livedoor.jp/maraigue/archives/1730713.html)

## C++17
VisualStudio2017/2019の場合、C++17 を有効にするには、C++プロジェクトのプロパティで **C/C++ ⇒ 言語 ⇒ C++言語標準** を **ISO C++17 Standard** 以上にする。

### 構造化束縛

いわゆる多値返却をそこそこ容易に実現出来るようになった :thumbsup::thumbsup::thumbsup: 

```c++
std::tuple<double, int, int> CalcAveMinMax(const char* filePath )
{
    // 画像ファイルを開いたとして

    // average, min, max を計算したりして
    double ave = 128;
    int min = 0, max = 255;

    // tuple に詰め込んで返す
    return { ave, min, max };
}

// 受け取り側はこんな感じ
auto[ aveValue, minValue, maxValue ] = CalcAveMinMax("file");
```

### 入れ子名前空間
インデントが無駄に深くならないようになった。ナイスアップデート:thumbsup: 

```c++:xxx.h
// 従来の書き方
namespace company {
    namespace product {
        namespace category {
            void func() { xxx; }
        }
    } 
}

// 新しい書き方
namespace company::product::category {
    void func() { xxx; }
}
```

参考: [入れ子名前空間の定義 - cpprefjp C++日本語リファレンス](https://cpprefjp.github.io/lang/cpp17/nested_namespace.html)

## その他参考ページ

[ゲーム開発者のための C++11/C++14](http://www.slideshare.net/Reputeless/c11c14)
ゲーム開発者じゃなくてもためになる。