はじめに
C++17は大型アップデートで、ものすごく便利な機能がたくさん追加された。
構造化束縛を使えるようになると、「C++17以前には戻れない」と思うようになるよ。
1. 構造化束縛
複数の値を一度に分解:
// ペア
pair<int, string> p = {42, "answer"};
auto [num, str] = p;
// タプル
tuple<int, double, string> t = {1, 3.14, "pi"};
auto [a, b, c] = t;
// 配列
int arr[] = {10, 20, 30};
auto [x, y, z] = arr;
// 構造体
struct Point { int x, y; };
auto [px, py] = Point{100, 200};
// mapのイテレーション
for (const auto& [key, value] : my_map) {
cout << key << ": " << value << endl;
}
2. if constexpr
コンパイル時分岐:
template<typename T>
string type_name() {
if constexpr (is_integral_v<T>) {
return "integral";
} else if constexpr (is_floating_point_v<T>) {
return "floating point";
} else {
return "other";
}
}
type_name<int>(); // "integral"
type_name<double>(); // "floating point"
3. if/switch 初期化文
スコープを限定した変数宣言:
// if文
if (auto it = m.find("key"); it != m.end()) {
cout << it->second << endl;
}
// itはここでスコープ外
// switch文
switch (int val = compute(); val) {
case 0: /* ... */ break;
case 1: /* ... */ break;
}
4. std::optional
値があるかもしれない型:
#include <optional>
optional<int> find_value(vector<int>& vec, int target) {
auto it = find(vec.begin(), vec.end(), target);
if (it != vec.end()) return *it;
return nullopt;
}
auto result = find_value(vec, 42);
if (result) {
cout << *result << endl;
}
// デフォルト値
cout << result.value_or(-1) << endl;
// メソッド
result.has_value(); // 値があるか
result.reset(); // 値をクリア
5. std::variant
型安全な共用体:
#include <variant>
variant<int, double, string> v;
v = 42;
cout << get<int>(v) << endl;
v = "Hello";
cout << get<string>(v) << endl;
// 現在の型を確認
v.index(); // 2
holds_alternative<string>(v); // true
// visitor
visit([](auto&& arg) {
cout << arg << endl;
}, v);
6. std::any
任意の型を保持:
#include <any>
any a = 42;
cout << any_cast<int>(a) << endl;
a = string("Hello");
cout << any_cast<string>(a) << endl;
// 型チェック
a.has_value();
a.type().name();
// 間違った型でキャストすると例外
try {
any_cast<int>(a); // bad_any_cast
} catch (const bad_any_cast& e) { }
7. std::string_view
文字列の軽量な参照:
#include <string_view>
void print(string_view sv) {
cout << sv << endl;
}
print("literal"); // コピーなし
print(some_string); // コピーなし
// 部分文字列
string_view sv = "Hello World";
sv.substr(0, 5); // "Hello"(コピーなし)
sv.remove_prefix(6); // "World"
利点:
- メモリ割り当てなし
-
const char*とstringの両方を受け取れる
8. 折り畳み式
可変長テンプレートの処理を簡潔に:
// 右畳み込み
template<typename... Args>
auto sum(Args... args) {
return (args + ...);
}
// 左畳み込み
template<typename... Args>
void print_all(Args... args) {
((cout << args << " "), ...);
}
sum(1, 2, 3, 4, 5); // 15
print_all("a", "b", "c"); // a b c
9. インライン変数
ヘッダーで変数を定義:
// header.h
struct Config {
inline static const string version = "1.0.0";
inline static int counter = 0;
};
ODR(One Definition Rule)違反を防げる。
10. constexpr lambda
ラムダ式をコンパイル時に評価:
constexpr auto square = [](int n) constexpr {
return n * n;
};
constexpr int result = square(5); // 25
// 配列サイズに使用可能
int arr[square(3)]; // int arr[9]
11. ネストした名前空間
// C++14以前
namespace A { namespace B { namespace C {
void func();
}}}
// C++17
namespace A::B::C {
void func();
}
12. 属性
// [[nodiscard]] - 戻り値を無視すると警告
[[nodiscard]] int compute();
// [[maybe_unused]] - 未使用の警告を抑制
[[maybe_unused]] int x = 42;
// [[fallthrough]] - 意図的なフォールスルー
switch (x) {
case 1:
do_something();
[[fallthrough]];
case 2:
do_more();
break;
}
13. std::filesystem
ファイルシステム操作:
#include <filesystem>
namespace fs = filesystem;
fs::path p = fs::current_path();
fs::path file = p / "test.txt";
// パス操作
file.filename(); // "test.txt"
file.extension(); // ".txt"
file.parent_path(); // 親ディレクトリ
// ファイル操作
fs::exists(file);
fs::is_directory(p);
fs::file_size(file);
fs::remove(file);
fs::copy(src, dst);
14. std::clamp
値を範囲内に制限:
clamp(10, 0, 100); // 10
clamp(-5, 0, 100); // 0
clamp(150, 0, 100); // 100
15. map の新メソッド
map<string, int> m;
// try_emplace: キーが存在しなければ追加
m.try_emplace("key", 1); // 追加
m.try_emplace("key", 100); // 既存なので無視
// insert_or_assign: 存在すれば更新
m.insert_or_assign("key", 100); // 更新
まとめ
| 機能 | 説明 |
|---|---|
| 構造化束縛 | auto [a, b] = pair |
if constexpr |
コンパイル時分岐 |
| if初期化 | if (auto x = ...; cond) |
optional |
値があるかもしれない型 |
variant |
型安全な共用体 |
any |
任意の型 |
string_view |
軽量な文字列参照 |
| 折り畳み式 | (args + ...) |
inline変数 |
ヘッダーでの変数定義 |
filesystem |
ファイル操作 |