はじめに
C++14はC++11のマイナーアップデート。
「そこまで大きな変更じゃないしスキップでいいか」って思うかもしれないけど、地味に便利な機能が多いんだよ。
1. ジェネリックラムダ
ラムダの引数にautoが使えるようになりました:
// C++11
auto add_int = [](int a, int b) { return a + b; };
// C++14(ジェネリック)
auto add = [](auto a, auto b) { return a + b; };
add(3, 4); // int
add(1.5, 2.5); // double
add(string("Hello"), string(" World")); // string
2. 戻り値型の推論
関数の戻り値型をautoで推論:
auto multiply(int a, int b) {
return a * b; // int と推論
}
auto factorial(int n) {
return (n <= 1) ? 1 : n * factorial(n - 1);
}
3. 変数テンプレート
テンプレート変数が定義可能に:
template<typename T>
constexpr T pi = T(3.14159265358979323846);
template<typename T>
constexpr T e = T(2.71828182845904523536);
// 使用
double area = pi<double> * r * r;
float val = e<float>;
4. 二進リテラル
0bプレフィックスでビット列を直接書ける:
int binary = 0b1010; // 10
int flags = 0b11110000; // 240
int mask = 0b00001111; // 15
// ビット操作がわかりやすい
int result = flags & mask; // 0b00000000 = 0
5. 桁区切り
大きな数値を読みやすく:
long long billion = 1'000'000'000; // 10億
double precise = 3.141'592'653'589'793;
int binary = 0b1111'0000'1111'0000;
int hex = 0xFF'FF'FF'FF;
6. decltype(auto)
参照型を保持して返す:
int global = 42;
int& get_ref() { return global; }
auto val = get_ref(); // int(コピー)
decltype(auto) ref = get_ref(); // int&(参照保持)
ref = 100; // globalが変わる
完全転送に便利:
template<typename F>
decltype(auto) wrapper(F f) {
return f(); // 戻り値の型を正確に転送
}
7. ラムダキャプチャの初期化
キャプチャ時に初期化式を書ける:
// ムーブキャプチャ
auto ptr = make_unique<int>(42);
auto lambda = [p = move(ptr)]() {
cout << *p;
};
// 計算結果をキャプチャ
int x = 10;
auto func = [y = x * 2]() {
return y; // 20
};
8. constexpr の拡張
C++14ではconstexpr関数内でループや変数が使用可能:
// C++11ではできなかった
constexpr int factorial(int n) {
int result = 1;
for (int i = 2; i <= n; ++i) {
result *= i;
}
return result;
}
constexpr int fibonacci(int n) {
if (n <= 1) return n;
int a = 0, b = 1;
for (int i = 2; i <= n; ++i) {
int temp = a + b;
a = b;
b = temp;
}
return b;
}
constexpr int fact10 = factorial(10); // コンパイル時計算
9. make_unique
unique_ptrを安全に作成:
// C++11(make_uniqueがない)
unique_ptr<int> p1(new int(42));
// C++14
auto p2 = make_unique<int>(42);
// 配列も可能
auto arr = make_unique<int[]>(10);
なぜmake_unique?
- 例外安全
-
newを直接書かなくて済む
10. std::exchange
値を設定して古い値を返す:
int a = 10;
int old = exchange(a, 20);
// old = 10, a = 20
// ムーブコンストラクタで便利
struct Data {
int* ptr;
Data(Data&& other) : ptr(exchange(other.ptr, nullptr)) {}
};
11. [[deprecated]] 属性
非推奨を明示:
[[deprecated("Use new_function() instead")]]
void old_function();
old_function(); // コンパイラ警告が出る
12. std::quoted
文字列をクォートで囲む:
#include <iomanip>
string text = "Hello World";
cout << quoted(text); // "Hello World"
string with_quotes = "He said \"Hello\"";
cout << quoted(with_quotes); // "He said \"Hello\""
まとめ
| 機能 | 説明 |
|---|---|
| ジェネリックラムダ |
auto引数のラムダ |
| 戻り値型推論 | 関数のauto戻り値 |
| 変数テンプレート | テンプレート変数 |
| 二進リテラル | 0b1010 |
| 桁区切り | 1'000'000 |
decltype(auto) |
型を保持する推論 |
| ラムダキャプチャ初期化 | [x = move(ptr)] |
| constexpr拡張 | ループ・変数が使用可能 |
make_unique |
unique_ptrの安全な作成 |
exchange |
値の入れ替え |
[[deprecated]] |
非推奨マーク |
quoted |
文字列のクォート |
まぁ、使いやすくなったよねってこと。